Hi,

I tried to backport Simon Riggs patches for 7.4.x series to 7.3.x
with addition of python implementation of pg_arch.

It can be of interest if you consider to continue using 7.3 series of postgresql.

src/backend/access/transam/xlog.c:  calls to "ereport" was replaced with call to 
"elog".
src/backend/utils/misc/guc.c :      format of "wal_archive" was converted to 7.3 style
src/bin/Makefile: was removed

Attached patch can be applied to 7.3.4 and 7.3.5

During this week I'll test it in our development enviroment.

Best regards

-- 
  Igor Poteryaev

Attachment: pg_arch.py
Description: application/python

*** src/backend/utils/misc/guc.c.orig  2004-04-27 23:08:24.000000000 +0100
--- src/backend/utils/misc/guc.c     2004-03-23 22:52:31.000000000 +0000
***************
*** 352,357 ****
--- 352,363 ----
  		{"fsync", PGC_SIGHUP}, &enableFsync,
  		true, NULL, NULL
  	},
+
+ 	{
+ 		{"wal_archive", PGC_SUSET}, &XLogArchivePolicy,
+ 		true, NULL, NULL
+ 	},
+
  	{
  		{"zero_damaged_pages", PGC_SUSET}, &zero_damaged_pages,
  		false, NULL, NULL
*** src/backend/access/transam/xlog.c.orig 2004-04-27 22:53:35.000000000 +0100
--- src/backend/access/transam/xlog.c    2004-04-27 22:01:15.000000000 +0100
***************
*** 84,96 ****
  
  
  /* User-settable parameters */
  int			CheckPointSegments = 3;
  int			XLOGbuffers = 8;
  int			XLOG_DEBUG = 0;
  char	   *XLOG_sync_method = NULL;
  const char	XLOG_sync_method_default[] = DEFAULT_SYNC_METHOD_STR;
- char		XLOG_archive_dir[MAXPGPATH];		/* null string means
- 												 * delete 'em */
  
  /*
   * XLOGfileslop is used in the code as the allowed "fuzz" in the number of
--- 84,95 ----
  
  
  /* User-settable parameters */
+ bool                  XLogArchivePolicy = false;
  int			CheckPointSegments = 3;
  int			XLOGbuffers = 8;
  int			XLOG_DEBUG = 0;
  char	   *XLOG_sync_method = NULL;
  const char	XLOG_sync_method_default[] = DEFAULT_SYNC_METHOD_STR;
  
  /*
   * XLOGfileslop is used in the code as the allowed "fuzz" in the number of
***************
*** 397,402 ****
--- 397,403 ----
  
  /* File path names */
  static char XLogDir[MAXPGPATH];
+ static char RLogDir[MAXPGPATH];
  static char ControlFilePath[MAXPGPATH];
  
  /*
***************
*** 438,443 ****
--- 438,451 ----
  
  static bool InRedo = false;
  
+ static bool XLogArchiveNotify(uint32 log, uint32 seg);
+ #define XLA_NOTIFY_OK  true
+ #define XLA_NOTIFY_ERROR false
+ 
+ static bool XLogArchiveBusy(char xlog[MAXPGPATH]);
+ #define XLA_BUSY       true
+ #define XLA_ARCHIVE_OK         false
+ #define XLA_BUSY_ERROR         2
  
  static bool AdvanceXLInsertBuffer(void);
  static void XLogWrite(XLogwrtRqst WriteRqst);
***************
*** 772,778 ****
  		MyProc->logRec = RecPtr;
  	}
  
! 	if (XLOG_DEBUG)
  	{
  		char		buf[8192];
  
--- 780,786 ----
  		MyProc->logRec = RecPtr;
  	}
  
! 	if (XLOG_DEBUG==16)
  	{
  		char		buf[8192];
  
***************
*** 878,883 ****
--- 886,1021 ----
  }

  /*
+  * XLogArchive API calls
+  *
+  * Two calls implement the PostgreSQL side of the XLogArchive API
+  *  XLogArchiveNotify
+  *  XLogArchiveBusy
+  */
+
+ /*
+  * XLogArchiveNotify
+  *
+  * Writes an archive notification file to the RLogDir
+  *
+  * The name of the notification file is the message that will be picked up
+  * by the archiver, e.g. we write RLogDir/00000001000000C6.full
+  * and the archiver then knows to archive XLOgDir/00000001000000C6,
+  * while it is doing so it will rename RLogDir/00000001000000C6.full
+  * to RLogDir/00000001000000C6.busy, then when complete, rename it again
+  * to RLogDir/00000001000000C6.done
+  *
+  * Called only when in wal_archive mode
+  */
+ static bool
+ XLogArchiveNotify(uint32 log, uint32 seg)
+ {
+       char            rlog[32];
+       char            rlogpath[MAXPGPATH];
+       FILE            *rlogFD;
+
+       if (XLOG_DEBUG)
+               elog(LOG, "XLogArchiveNotify writing notification for log file %u, segment %u",
+                                                  log, seg);
+
+ /* insert an otherwise empty file called <XLOG>.full */
+       sprintf(rlog, "%08X%08X.full", log, seg);
+       snprintf(rlogpath, MAXPGPATH, "%s/%s", RLogDir, rlog);
+       rlogFD = AllocateFile(rlogpath, "w");
+       if (rlogFD == NULL)
+               elog(ERROR,
+                       "could not write XLogArchive API Notify file \"%s\" ",
+                                  rlogpath);
+       FreeFile(rlogFD);
+ /* the existence of this file is the message to the archiver to begin archiving */
+ /* the file <XLOG> from the pg_xlog directory                                 */
+
+       if (XLOG_DEBUG)
+               elog(LOG, "XLogArchiveNotify written: %s", rlogpath );
+
+       return XLA_NOTIFY_OK;
+ }
+
+ /*
+  * XLogArchiveBusy
+  *
+  * Searches for an archive notification file in RLogDir
+  *
+  * Reads RLogDir looking for a specific filename. If that filename ends with .done
+  * then we know that the filename refers to an xlog in XLogDir that is safe to
+  * recycle. If the filename ends .full or .busy then thats OK, if neither then
+  * we have an error.
+  *
+  * Called only when in wal_archive mode
+  *
+  */
+ static bool
+ XLogArchiveBusy(char xlog[32])
+ {
+       char            rlogpath[MAXPGPATH];
+       FILE            *rlogFD;
+
+       if (XLOG_DEBUG)
+               elog(LOG, "XLogArchiveBusy check for log file %s",
+                                                  xlog);
+
+ /* If <XLOG>.done exists then return XLA_ARCHIVE_OK           */
+       snprintf(rlogpath, MAXPGPATH, "%s/%s.done", RLogDir, xlog);
+       rlogFD = AllocateFile(rlogpath, "r");
+       if (rlogFD != NULL) {
+               FreeFile(rlogFD);
+               if (XLOG_DEBUG)
+                       elog(LOG, "XLogArchiveBusy shows archiving done for log file %s",
+                                                  xlog);
+               /* really ought to wait until after xlog recycled, in case there */
+               /* is an error between the two activities -- do that later       */
+               unlink(rlogpath);
+               return XLA_ARCHIVE_OK;
+       }
+       else
+       {
+ /* else if <XLOG>.busy exists then return XLA_BUSY            */
+               snprintf(rlogpath, MAXPGPATH, "%s/%s.busy", RLogDir, xlog);
+               rlogFD = AllocateFile(rlogpath, "r");
+               if (rlogFD != NULL) {
+                       FreeFile(rlogFD);
+                       elog(LOG, "XLogArchive shows archiving still busy for log file %s",
+                                               xlog);
+                       /* Do something clever here to avoid systematic or one-off      */
+                       /* time delays from effecting server stability                  */
+                       return XLA_BUSY;
+               }
+               else
+               {
+ /*
+  * else if <XLOG>.full exists then return XLA_BUSY and issue WARNING
+  * ...this indicates archiver is either not working at all or
+  * if it is, then its just way too slow or incorrectly configured
+  */
+                       snprintf(rlogpath, MAXPGPATH, "%s/%s.full", RLogDir, xlog);
+                       rlogFD = AllocateFile(rlogpath, "r");
+                       if (rlogFD != NULL) {
+                           FreeFile(rlogFD);
+                           elog(WARNING, "XLogArchive shows archiving not yet started for log file %s",
+                                               xlog);
+                           return XLA_BUSY;
+                       }
+                       else
+                       {
+ /* else issue a WARNING.... a notification file SHOULD exist...unless #Bug2..the
+  * database has just been restored in which case it may be absent, so
+  * issue a WARNING, not an error, then return
+  */
+                           elog(WARNING,
+                               "cannot find XLogArchive notification file: %s ",
+                                               rlogpath);
+                           return XLA_ARCHIVE_OK;
+                       }
+               }
+       }
+ }
+
+ /*
   * Advance the Insert state to the next buffer page, writing out the next
   * buffer if it still contains unwritten data.
   *
***************
*** 1126,1131 ****
--- 1268,1278 ----
  		{
  			issue_xlog_fsync();
  			LogwrtResult.Flush = LogwrtResult.Write;	/* end of current page */
+
+                       /* Notify xlog ready to archive?*/
+                       if (XLogArchivePolicy && !XLogArchiveNotify(openLogId, openLogSeg))
+                               elog(WARNING, "could not set notify for archiver to read log file %u, segment %u",
+                                          openLogId, openLogSeg);
  		}
  
  		if (ispartialpage)
***************
*** 1204,1210 ****
  	XLogRecPtr	WriteRqstPtr;
  	XLogwrtRqst WriteRqst;
  
! 	if (XLOG_DEBUG)
  	{
  		elog(LOG, "XLogFlush%s%s: request %X/%X; write %X/%X; flush %X/%X",
  			 (IsBootstrapProcessingMode()) ? "(bootstrap)" : "",
--- 1351,1357 ----
  	XLogRecPtr	WriteRqstPtr;
  	XLogwrtRqst WriteRqst;
  
! 	if (XLOG_DEBUG==16)
  	{
  		elog(LOG, "XLogFlush%s%s: request %X/%X; write %X/%X; flush %X/%X",
  			 (IsBootstrapProcessingMode()) ? "(bootstrap)" : "",
***************
*** 1607,1630 ****
  	errno = 0;
  	while ((xlde = readdir(xldir)) != NULL)
  	{
  		if (strlen(xlde->d_name) == 16 &&
  			strspn(xlde->d_name, "0123456789ABCDEF") == 16 &&
  			strcmp(xlde->d_name, lastoff) <= 0)
  		{
  			snprintf(path, MAXPGPATH, "%s/%s", XLogDir, xlde->d_name);
! 			if (XLOG_archive_dir[0])
! 			{
! 				elog(LOG, "archiving transaction log file %s",
! 					 xlde->d_name);
! 				elog(WARNING, "archiving log files is not implemented!");
! 			}
! 			else
  			{
  				/*
  				 * Before deleting the file, see if it can be recycled as
  				 * a future log segment.  We allow recycling segments up
! 				 * to XLOGfileslop segments beyond the current XLOG
! 				 * location.
  				 */
  				if (InstallXLogFileSegment(endlogId, endlogSeg, path,
  										   true, XLOGfileslop,
--- 1754,1779 ----
  	errno = 0;
  	while ((xlde = readdir(xldir)) != NULL)
  	{
+               /* if correct length and alphanumeric makeup of file looks correct      */
+               /* use the alphanumeric sorting property of the filenames to decide     */
+               /* which ones are earlier than the lastoff transaction log              */
+               /* ...maybe should read lastwrite datetime of lastoff, then check that  */
+               /* only files last written earlier than this are removed/recycled       */
  		if (strlen(xlde->d_name) == 16 &&
  			strspn(xlde->d_name, "0123456789ABCDEF") == 16 &&
  			strcmp(xlde->d_name, lastoff) <= 0)
  		{
  			snprintf(path, MAXPGPATH, "%s/%s", XLogDir, xlde->d_name);
!
!                       if ( !XLogArchivePolicy ||
!                               (XLogArchivePolicy && !XLogArchiveBusy(xlde->d_name))
!                          )
  			{
  				/*
  				 * Before deleting the file, see if it can be recycled as
  				 * a future log segment.  We allow recycling segments up
!                                * until there are XLOGfileslop segments beyond the
!                                * current XLOG location, otherwise they are removed.
  				 */
  				if (InstallXLogFileSegment(endlogId, endlogSeg, path,
  										   true, XLOGfileslop,
***************
*** 1636,1645 ****
  				else
  				{
  					/* No need for any more future segments... */
! 					elog(LOG, "removing transaction log file %s",
  						 xlde->d_name);
  					unlink(path);
  				}
  			}
  		}
  		errno = 0;
--- 1784,1797 ----
  				else
  				{
  					/* No need for any more future segments... */
! 					elog(LOG, "too many transaction log files, removing %s",
  						 xlde->d_name);
  					unlink(path);
  				}
+                               /*
+                               if (XLogArchivePolicy && !XLogArchiveBusy(xlde->d_name))
+                                       XLogArchiveUnNotify(xlde->d_name);
+                                */
  			}
  		}
  		errno = 0;
***************
*** 2067,2072 ****
--- 2219,2225 ----
  {
  	/* Init XLOG file paths */
  	snprintf(XLogDir, MAXPGPATH, "%s/pg_xlog", DataDir);
+       snprintf(RLogDir, MAXPGPATH, "%s/pg_rlog", DataDir);
  	snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
  }
  
***************
*** 2624,2630 ****
  					ShmemVariableCache->nextXid = record->xl_xid;
  					TransactionIdAdvance(ShmemVariableCache->nextXid);
  				}
! 				if (XLOG_DEBUG)
  				{
  					char		buf[8192];
  
--- 2777,2783 ----
  					ShmemVariableCache->nextXid = record->xl_xid;
  					TransactionIdAdvance(ShmemVariableCache->nextXid);
  				}
! 				if (XLOG_DEBUG==16)
  				{
  					char		buf[8192];
  
*** src/include/access/xlog.h.orig 2004-04-27 23:05:29.000000000 +0100
--- src/include/access/xlog.h    2004-04-27 23:05:37.000000000 +0100
***************
*** 188,194 ****
  extern int	XLOG_DEBUG;
  extern char *XLOG_sync_method;
  extern const char XLOG_sync_method_default[];
! 
  
  extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
  extern void XLogFlush(XLogRecPtr RecPtr);
--- 188,194 ----
  extern int	XLOG_DEBUG;
  extern char *XLOG_sync_method;
  extern const char XLOG_sync_method_default[];
! extern bool   XLogArchivePolicy;
  
  extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
  extern void XLogFlush(XLogRecPtr RecPtr);
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

               http://archives.postgresql.org
  • ... Потеряев И.Е.
    • ... Tom Lane
      • ... Потеряев И.Е.
        • ... Joshua D. Drake

Reply via email to