WIP patch to perform a switch from one log file to next when we do a
pg_stop_backup(), including wal replay handling at recovery time.
Patch currently crashes server at various points, so don't stare too
hard, but patch applies cleanly on cvstip, compiles and make checks.
Main issue is the need to poke the xlog record pointer with a new value
after the log switch. I'm a little uncertain about that approach and I'm
very likely getting it wrong now. Better ideas welcome.
Patch is incomplete in that it doesn't handle shutdown checkpoints as
log switches in archive mode (yet)
Also nothing in here about standby databases (yet)
Any comments appreciated before I spend too much time on this.
Best Regards, Simon Riggs
Index: src/backend/access/transam/xlog.c
===
RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/xlog.c,v
retrieving revision 1.187
diff -d -c -r1.187 xlog.c
*** src/backend/access/transam/xlog.c 17 Apr 2005 03:04:29 - 1.187
--- src/backend/access/transam/xlog.c 19 Apr 2005 18:31:27 -
***
*** 403,408
--- 403,410
static uint32 openLogId = 0;
static uint32 openLogSeg = 0;
static uint32 openLogOff = 0;
+ static uint32 newLogId = 0; /* used when switching log segment file */
+ static uint32 newLogSeg = 0;
/*
* These variables are used similarly to the ones above, but for reading
***
*** 428,433
--- 430,437
static XLogRecord *nextRecord = NULL;
static TimeLineID lastPageTLI = 0;
+ static bool PerformSwitchXLogFile = false;
+
static bool InRedo = false;
***
*** 442,447
--- 446,452
static bool AdvanceXLInsertBuffer(void);
static void XLogWrite(XLogwrtRqst WriteRqst);
+ static void XLogSwitchLogSegment(void);
static int XLogFileInit(uint32 log, uint32 seg,
bool *use_existent, bool use_lock);
static bool InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath,
***
*** 1150,1156
XLogCtlWrite *Write = &XLogCtl->Write;
char *from;
bool ispartialpage;
- bool use_existent;
/* We should always be inside a critical section here */
Assert(CritSectionCount > 0);
--- 1155,1160
***
*** 1181,1253
if (!XLByteInPrevSeg(LogwrtResult.Write, openLogId, openLogSeg))
{
! /*
! * Switch to new logfile segment.
! */
! if (openLogFile >= 0)
! {
! if (close(openLogFile))
! ereport(PANIC,
! (errcode_for_file_access(),
! errmsg("could not close log file %u, segment %u: %m",
! openLogId, openLogSeg)));
! openLogFile = -1;
! }
! XLByteToPrevSeg(LogwrtResult.Write, openLogId, openLogSeg);
!
! /* create/use new log file */
! use_existent = true;
! openLogFile = XLogFileInit(openLogId, openLogSeg,
! &use_existent, true);
! openLogOff = 0;
!
! /* update pg_control, unless someone else already did */
! LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
! if (ControlFile->logId < openLogId ||
! (ControlFile->logId == openLogId &&
! ControlFile->logSeg < openLogSeg + 1))
! {
! ControlFile->logId = openLogId;
! ControlFile->logSeg = openLogSeg + 1;
! ControlFile->time = time(NULL);
! UpdateControlFile();
!
! /*
! * Signal bgwriter to start a checkpoint if it's been
! * too long since the last one. (We look at local copy of
! * RedoRecPtr which might be a little out of date, but
! * should be close enough for this purpose.)
! *
! * A straight computation of segment number could overflow
! * 32 bits. Rather than assuming we have working 64-bit
! * arithmetic, we compare the highest-order bits separately,
! * and force a checkpoint immediately when they change.
! */
! if (IsUnderPostmaster)
! {
! uint32 old_segno,
! new_segno;
! uint32 old_highbits,
! new_highbits;
!
! old_segno = (RedoRecPtr.xlogid % XLogSegSize) * XLogSegsPerFile +
! (RedoRecPtr.xrecoff / XLogSegSize);
! old_highbits = RedoRecPtr.xlogid / XLogSegSize;
! new_segno = (openLogId % XLogSegSize) * XLogSegsPerFile +
! openLogSeg;
! new_highbits = openLogId / XLogSegSize;
! if (new_highbits != old_highbits ||
! new_segno >= old_segno + (uint32) CheckPointSegments)
! {
! #ifdef WAL_DEBUG
! if (XLOG_DEBUG)
! elog(LOG, "time for a checkpoint, signaling bgwriter");
! #endif
! RequestCheckpoint(false);
! }
! }
! }
! LWLockRelease(ControlFileLock);
}
if (openLogFile < 0)
--- 1185,1191
if (!XLByteInPrevSeg(LogwrtResult.Write, openLogId, openLogSeg))
{
! XLogSwitchLogSegment();
}
if (openLogFile < 0)
***
*** 1285,1290
--- 1223,1229
/*
* If we just wrote the whole last page of a logfile segment,
+ * or if we have been instructed to switch