Commit dfda6eba authored by Heikki Linnakangas's avatar Heikki Linnakangas

Don't waste the last segment of each 4GB logical log file.

The comments claimed that wasting the last segment made it easier to do
calculations with XLogRecPtrs, because you don't have problems representing
last-byte-position-plus-1 that way. In my experience, however, it only made
things more complicated, because the there was two ways to represent the
boundary at the beginning of a logical log file: logid = n+1 and xrecoff = 0,
or as xlogid = n and xrecoff = 4GB - XLOG_SEG_SIZE. Some functions were
picky about which representation was used.

Also, use a 64-bit segment number instead of the log/seg combination, to
point to a certain WAL segment. We assume that all platforms have a working
64-bit integer type nowadays.

This is an incompatible change in WAL format, so bumping WAL version number.
parent 47c7365e
...@@ -385,8 +385,7 @@ typedef struct XLogCtlData ...@@ -385,8 +385,7 @@ typedef struct XLogCtlData
uint32 ckptXidEpoch; /* nextXID & epoch of latest checkpoint */ uint32 ckptXidEpoch; /* nextXID & epoch of latest checkpoint */
TransactionId ckptXid; TransactionId ckptXid;
XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */ XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */
uint32 lastRemovedLog; /* latest removed/recycled XLOG segment */ XLogSegNo lastRemovedSegNo; /* latest removed/recycled XLOG segment */
uint32 lastRemovedSeg;
/* Protected by WALWriteLock: */ /* Protected by WALWriteLock: */
XLogCtlWrite Write; XLogCtlWrite Write;
...@@ -494,11 +493,13 @@ static ControlFileData *ControlFile = NULL; ...@@ -494,11 +493,13 @@ static ControlFileData *ControlFile = NULL;
/* Construct XLogRecPtr value for current insertion point */ /* Construct XLogRecPtr value for current insertion point */
#define INSERT_RECPTR(recptr,Insert,curridx) \ #define INSERT_RECPTR(recptr,Insert,curridx) \
( \ do { \
(recptr).xlogid = XLogCtl->xlblocks[curridx].xlogid, \ (recptr).xlogid = XLogCtl->xlblocks[curridx].xlogid; \
(recptr).xrecoff = \ (recptr).xrecoff = \
XLogCtl->xlblocks[curridx].xrecoff - INSERT_FREESPACE(Insert) \ XLogCtl->xlblocks[curridx].xrecoff - INSERT_FREESPACE(Insert); \
) if (XLogCtl->xlblocks[curridx].xrecoff == 0) \
(recptr).xlogid = XLogCtl->xlblocks[curridx].xlogid - 1; \
} while(0)
#define PrevBufIdx(idx) \ #define PrevBufIdx(idx) \
(((idx) == 0) ? XLogCtl->XLogCacheBlck : ((idx) - 1)) (((idx) == 0) ? XLogCtl->XLogCacheBlck : ((idx) - 1))
...@@ -524,12 +525,11 @@ static XLogwrtResult LogwrtResult = {{0, 0}, {0, 0}}; ...@@ -524,12 +525,11 @@ static XLogwrtResult LogwrtResult = {{0, 0}, {0, 0}};
/* /*
* openLogFile is -1 or a kernel FD for an open log file segment. * openLogFile is -1 or a kernel FD for an open log file segment.
* When it's open, openLogOff is the current seek offset in the file. * When it's open, openLogOff is the current seek offset in the file.
* openLogId/openLogSeg identify the segment. These variables are only * openLogSegNo identifies the segment. These variables are only
* used to write the XLOG, and so will normally refer to the active segment. * used to write the XLOG, and so will normally refer to the active segment.
*/ */
static int openLogFile = -1; static int openLogFile = -1;
static uint32 openLogId = 0; static XLogSegNo openLogSegNo = 0;
static uint32 openLogSeg = 0;
static uint32 openLogOff = 0; static uint32 openLogOff = 0;
/* /*
...@@ -541,8 +541,7 @@ static uint32 openLogOff = 0; ...@@ -541,8 +541,7 @@ static uint32 openLogOff = 0;
* the currently open file from. * the currently open file from.
*/ */
static int readFile = -1; static int readFile = -1;
static uint32 readId = 0; static XLogSegNo readSegNo = 0;
static uint32 readSeg = 0;
static uint32 readOff = 0; static uint32 readOff = 0;
static uint32 readLen = 0; static uint32 readLen = 0;
static int readSource = 0; /* XLOG_FROM_* code */ static int readSource = 0; /* XLOG_FROM_* code */
...@@ -611,13 +610,12 @@ typedef struct xl_restore_point ...@@ -611,13 +610,12 @@ typedef struct xl_restore_point
static void XLogArchiveNotify(const char *xlog); static void XLogArchiveNotify(const char *xlog);
static void XLogArchiveNotifySeg(uint32 log, uint32 seg); static void XLogArchiveNotifySeg(XLogSegNo segno);
static bool XLogArchiveCheckDone(const char *xlog); static bool XLogArchiveCheckDone(const char *xlog);
static bool XLogArchiveIsBusy(const char *xlog); static bool XLogArchiveIsBusy(const char *xlog);
static void XLogArchiveCleanup(const char *xlog); static void XLogArchiveCleanup(const char *xlog);
static void readRecoveryCommandFile(void); static void readRecoveryCommandFile(void);
static void exitArchiveRecovery(TimeLineID endTLI, static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
uint32 endLogId, uint32 endLogSeg);
static bool recoveryStopsHere(XLogRecord *record, bool *includeThis); static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
static void recoveryPausesHere(void); static void recoveryPausesHere(void);
static void SetLatestXTime(TimestampTz xtime); static void SetLatestXTime(TimestampTz xtime);
...@@ -626,20 +624,19 @@ static void CheckRequiredParameterValues(void); ...@@ -626,20 +624,19 @@ static void CheckRequiredParameterValues(void);
static void XLogReportParameters(void); static void XLogReportParameters(void);
static void LocalSetXLogInsertAllowed(void); static void LocalSetXLogInsertAllowed(void);
static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags); static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
static void KeepLogSeg(XLogRecPtr recptr, uint32 *logId, uint32 *logSeg); static void KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo);
static bool XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites, static bool XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites,
XLogRecPtr *lsn, BkpBlock *bkpb); XLogRecPtr *lsn, BkpBlock *bkpb);
static bool AdvanceXLInsertBuffer(bool new_segment); static bool AdvanceXLInsertBuffer(bool new_segment);
static bool XLogCheckpointNeeded(uint32 logid, uint32 logseg); static bool XLogCheckpointNeeded(XLogSegNo new_segno);
static void XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch); static void XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch);
static bool InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath, static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
bool find_free, int *max_advance, bool find_free, int *max_advance,
bool use_lock); bool use_lock);
static int XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli, static int XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
int source, bool notexistOk); int source, bool notexistOk);
static int XLogFileReadAnyTLI(uint32 log, uint32 seg, int emode, static int XLogFileReadAnyTLI(XLogSegNo segno, int emode, int sources);
int sources);
static bool XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt, static bool XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
bool randAccess); bool randAccess);
static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr); static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr);
...@@ -649,7 +646,7 @@ static bool RestoreArchivedFile(char *path, const char *xlogfname, ...@@ -649,7 +646,7 @@ static bool RestoreArchivedFile(char *path, const char *xlogfname,
static void ExecuteRecoveryCommand(char *command, char *commandName, static void ExecuteRecoveryCommand(char *command, char *commandName,
bool failOnerror); bool failOnerror);
static void PreallocXlogFiles(XLogRecPtr endptr); static void PreallocXlogFiles(XLogRecPtr endptr);
static void RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr); static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr endptr);
static void UpdateLastRemovedPtr(char *filename); static void UpdateLastRemovedPtr(char *filename);
static void ValidateXLOGDirectoryStructure(void); static void ValidateXLOGDirectoryStructure(void);
static void CleanupBackupHistory(void); static void CleanupBackupHistory(void);
...@@ -663,8 +660,7 @@ static bool existsTimeLineHistory(TimeLineID probeTLI); ...@@ -663,8 +660,7 @@ static bool existsTimeLineHistory(TimeLineID probeTLI);
static bool rescanLatestTimeLine(void); static bool rescanLatestTimeLine(void);
static TimeLineID findNewestTimeLine(TimeLineID startTLI); static TimeLineID findNewestTimeLine(TimeLineID startTLI);
static void writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, static void writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
TimeLineID endTLI, TimeLineID endTLI, XLogSegNo endLogSegNo);
uint32 endLogId, uint32 endLogSeg);
static void WriteControlFile(void); static void WriteControlFile(void);
static void ReadControlFile(void); static void ReadControlFile(void);
static char *str_time(pg_time_t tnow); static char *str_time(pg_time_t tnow);
...@@ -996,12 +992,6 @@ begin:; ...@@ -996,12 +992,6 @@ begin:;
LWLockRelease(WALInsertLock); LWLockRelease(WALInsertLock);
RecPtr.xrecoff -= SizeOfXLogLongPHD; RecPtr.xrecoff -= SizeOfXLogLongPHD;
if (RecPtr.xrecoff == 0)
{
/* crossing a logid boundary */
RecPtr.xlogid -= 1;
RecPtr.xrecoff = XLogFileSize;
}
LWLockAcquire(WALWriteLock, LW_EXCLUSIVE); LWLockAcquire(WALWriteLock, LW_EXCLUSIVE);
LogwrtResult = XLogCtl->LogwrtResult; LogwrtResult = XLogCtl->LogwrtResult;
...@@ -1148,13 +1138,12 @@ begin:; ...@@ -1148,13 +1138,12 @@ begin:;
/* Compute end address of old segment */ /* Compute end address of old segment */
OldSegEnd = XLogCtl->xlblocks[curridx]; OldSegEnd = XLogCtl->xlblocks[curridx];
OldSegEnd.xrecoff -= XLOG_BLCKSZ;
if (OldSegEnd.xrecoff == 0) if (OldSegEnd.xrecoff == 0)
{ {
/* crossing a logid boundary */ /* crossing a logid boundary */
OldSegEnd.xlogid -= 1; OldSegEnd.xlogid -= 1;
OldSegEnd.xrecoff = XLogFileSize;
} }
OldSegEnd.xrecoff -= XLOG_BLCKSZ;
/* Make it look like we've written and synced all of old segment */ /* Make it look like we've written and synced all of old segment */
LogwrtResult.Write = OldSegEnd; LogwrtResult.Write = OldSegEnd;
...@@ -1324,14 +1313,14 @@ XLogArchiveNotify(const char *xlog) ...@@ -1324,14 +1313,14 @@ XLogArchiveNotify(const char *xlog)
} }
/* /*
* Convenience routine to notify using log/seg representation of filename * Convenience routine to notify using segment number representation of filename
*/ */
static void static void
XLogArchiveNotifySeg(uint32 log, uint32 seg) XLogArchiveNotifySeg(XLogSegNo segno)
{ {
char xlog[MAXFNAMELEN]; char xlog[MAXFNAMELEN];
XLogFileName(xlog, ThisTimeLineID, log, seg); XLogFileName(xlog, ThisTimeLineID, segno);
XLogArchiveNotify(xlog); XLogArchiveNotify(xlog);
} }
...@@ -1468,6 +1457,7 @@ AdvanceXLInsertBuffer(bool new_segment) ...@@ -1468,6 +1457,7 @@ AdvanceXLInsertBuffer(bool new_segment)
XLogRecPtr OldPageRqstPtr; XLogRecPtr OldPageRqstPtr;
XLogwrtRqst WriteRqst; XLogwrtRqst WriteRqst;
XLogRecPtr NewPageEndPtr; XLogRecPtr NewPageEndPtr;
XLogRecPtr NewPageBeginPtr;
XLogPageHeader NewPage; XLogPageHeader NewPage;
/* /*
...@@ -1532,23 +1522,18 @@ AdvanceXLInsertBuffer(bool new_segment) ...@@ -1532,23 +1522,18 @@ AdvanceXLInsertBuffer(bool new_segment)
* Now the next buffer slot is free and we can set it up to be the next * Now the next buffer slot is free and we can set it up to be the next
* output page. * output page.
*/ */
NewPageEndPtr = XLogCtl->xlblocks[Insert->curridx]; NewPageBeginPtr = XLogCtl->xlblocks[Insert->curridx];
if (new_segment) if (new_segment)
{ {
/* force it to a segment start point */ /* force it to a segment start point */
NewPageEndPtr.xrecoff += XLogSegSize - 1; if (NewPageBeginPtr.xrecoff % XLogSegSize != 0)
NewPageEndPtr.xrecoff -= NewPageEndPtr.xrecoff % XLogSegSize; XLByteAdvance(NewPageBeginPtr,
XLogSegSize - NewPageBeginPtr.xrecoff % XLogSegSize);
} }
if (NewPageEndPtr.xrecoff >= XLogFileSize) NewPageEndPtr = NewPageBeginPtr;
{ XLByteAdvance(NewPageEndPtr, XLOG_BLCKSZ);
/* crossing a logid boundary */
NewPageEndPtr.xlogid += 1;
NewPageEndPtr.xrecoff = XLOG_BLCKSZ;
}
else
NewPageEndPtr.xrecoff += XLOG_BLCKSZ;
XLogCtl->xlblocks[nextidx] = NewPageEndPtr; XLogCtl->xlblocks[nextidx] = NewPageEndPtr;
NewPage = (XLogPageHeader) (XLogCtl->pages + nextidx * (Size) XLOG_BLCKSZ); NewPage = (XLogPageHeader) (XLogCtl->pages + nextidx * (Size) XLOG_BLCKSZ);
...@@ -1570,8 +1555,7 @@ AdvanceXLInsertBuffer(bool new_segment) ...@@ -1570,8 +1555,7 @@ AdvanceXLInsertBuffer(bool new_segment)
/* NewPage->xlp_info = 0; */ /* done by memset */ /* NewPage->xlp_info = 0; */ /* done by memset */
NewPage ->xlp_tli = ThisTimeLineID; NewPage ->xlp_tli = ThisTimeLineID;
NewPage ->xlp_pageaddr.xlogid = NewPageEndPtr.xlogid; NewPage ->xlp_pageaddr = NewPageBeginPtr;
NewPage ->xlp_pageaddr.xrecoff = NewPageEndPtr.xrecoff - XLOG_BLCKSZ;
/* /*
* If online backup is not in progress, mark the header to indicate that * If online backup is not in progress, mark the header to indicate that
...@@ -1609,33 +1593,20 @@ AdvanceXLInsertBuffer(bool new_segment) ...@@ -1609,33 +1593,20 @@ AdvanceXLInsertBuffer(bool new_segment)
/* /*
* Check whether we've consumed enough xlog space that a checkpoint is needed. * Check whether we've consumed enough xlog space that a checkpoint is needed.
* *
* logid/logseg indicate a log file that has just been filled up (or read * new_segno indicates a log file that has just been filled up (or read
* during recovery). We measure the distance from RedoRecPtr to logid/logseg * during recovery). We measure the distance from RedoRecPtr to new_segno
* and see if that exceeds CheckPointSegments. * and see if that exceeds CheckPointSegments.
* *
* Note: it is caller's responsibility that RedoRecPtr is up-to-date. * Note: it is caller's responsibility that RedoRecPtr is up-to-date.
*/ */
static bool static bool
XLogCheckpointNeeded(uint32 logid, uint32 logseg) XLogCheckpointNeeded(XLogSegNo new_segno)
{ {
/* XLogSegNo old_segno;
* A straight computation of segment number could overflow 32 bits. Rather
* than assuming we have working 64-bit arithmetic, we compare the XLByteToSeg(RedoRecPtr, old_segno);
* highest-order bits separately, and force a checkpoint immediately when
* they change. if (new_segno >= old_segno + (uint64) (CheckPointSegments - 1))
*/
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 = (logid % XLogSegSize) * XLogSegsPerFile + logseg;
new_highbits = logid / XLogSegSize;
if (new_highbits != old_highbits ||
new_segno >= old_segno + (uint32) (CheckPointSegments - 1))
return true; return true;
return false; return false;
} }
...@@ -1716,7 +1687,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch) ...@@ -1716,7 +1687,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
LogwrtResult.Write = XLogCtl->xlblocks[curridx]; LogwrtResult.Write = XLogCtl->xlblocks[curridx];
ispartialpage = XLByteLT(WriteRqst.Write, LogwrtResult.Write); ispartialpage = XLByteLT(WriteRqst.Write, LogwrtResult.Write);
if (!XLByteInPrevSeg(LogwrtResult.Write, openLogId, openLogSeg)) if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo))
{ {
/* /*
* Switch to new logfile segment. We cannot have any pending * Switch to new logfile segment. We cannot have any pending
...@@ -1725,20 +1696,19 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch) ...@@ -1725,20 +1696,19 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
Assert(npages == 0); Assert(npages == 0);
if (openLogFile >= 0) if (openLogFile >= 0)
XLogFileClose(); XLogFileClose();
XLByteToPrevSeg(LogwrtResult.Write, openLogId, openLogSeg); XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo);
/* create/use new log file */ /* create/use new log file */
use_existent = true; use_existent = true;
openLogFile = XLogFileInit(openLogId, openLogSeg, openLogFile = XLogFileInit(openLogSegNo, &use_existent, true);
&use_existent, true);
openLogOff = 0; openLogOff = 0;
} }
/* Make sure we have the current logfile open */ /* Make sure we have the current logfile open */
if (openLogFile < 0) if (openLogFile < 0)
{ {
XLByteToPrevSeg(LogwrtResult.Write, openLogId, openLogSeg); XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo);
openLogFile = XLogFileOpen(openLogId, openLogSeg); openLogFile = XLogFileOpen(openLogSegNo);
openLogOff = 0; openLogOff = 0;
} }
...@@ -1775,9 +1745,9 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch) ...@@ -1775,9 +1745,9 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
if (lseek(openLogFile, (off_t) startoffset, SEEK_SET) < 0) if (lseek(openLogFile, (off_t) startoffset, SEEK_SET) < 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not seek in log file %u, " errmsg("could not seek in log file %s to offset %u: %m",
"segment %u to offset %u: %m", XLogFileNameP(ThisTimeLineID, openLogSegNo),
openLogId, openLogSeg, startoffset))); startoffset)));
openLogOff = startoffset; openLogOff = startoffset;
} }
...@@ -1792,9 +1762,9 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch) ...@@ -1792,9 +1762,9 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
errno = ENOSPC; errno = ENOSPC;
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write to log file %u, segment %u " errmsg("could not write to log file %s "
"at offset %u, length %lu: %m", "at offset %u, length %lu: %m",
openLogId, openLogSeg, XLogFileNameP(ThisTimeLineID, openLogSegNo),
openLogOff, (unsigned long) nbytes))); openLogOff, (unsigned long) nbytes)));
} }
...@@ -1821,11 +1791,11 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch) ...@@ -1821,11 +1791,11 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
*/ */
if (finishing_seg || (xlog_switch && last_iteration)) if (finishing_seg || (xlog_switch && last_iteration))
{ {
issue_xlog_fsync(openLogFile, openLogId, openLogSeg); issue_xlog_fsync(openLogFile, openLogSegNo);
LogwrtResult.Flush = LogwrtResult.Write; /* end of page */ LogwrtResult.Flush = LogwrtResult.Write; /* end of page */
if (XLogArchivingActive()) if (XLogArchivingActive())
XLogArchiveNotifySeg(openLogId, openLogSeg); XLogArchiveNotifySeg(openLogSegNo);
Write->lastSegSwitchTime = (pg_time_t) time(NULL); Write->lastSegSwitchTime = (pg_time_t) time(NULL);
...@@ -1836,11 +1806,10 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch) ...@@ -1836,11 +1806,10 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
* like a checkpoint is needed, forcibly update RedoRecPtr and * like a checkpoint is needed, forcibly update RedoRecPtr and
* recheck. * recheck.
*/ */
if (IsUnderPostmaster && if (IsUnderPostmaster && XLogCheckpointNeeded(openLogSegNo))
XLogCheckpointNeeded(openLogId, openLogSeg))
{ {
(void) GetRedoRecPtr(); (void) GetRedoRecPtr();
if (XLogCheckpointNeeded(openLogId, openLogSeg)) if (XLogCheckpointNeeded(openLogSegNo))
RequestCheckpoint(CHECKPOINT_CAUSE_XLOG); RequestCheckpoint(CHECKPOINT_CAUSE_XLOG);
} }
} }
...@@ -1877,15 +1846,15 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch) ...@@ -1877,15 +1846,15 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
sync_method != SYNC_METHOD_OPEN_DSYNC) sync_method != SYNC_METHOD_OPEN_DSYNC)
{ {
if (openLogFile >= 0 && if (openLogFile >= 0 &&
!XLByteInPrevSeg(LogwrtResult.Write, openLogId, openLogSeg)) !XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo))
XLogFileClose(); XLogFileClose();
if (openLogFile < 0) if (openLogFile < 0)
{ {
XLByteToPrevSeg(LogwrtResult.Write, openLogId, openLogSeg); XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo);
openLogFile = XLogFileOpen(openLogId, openLogSeg); openLogFile = XLogFileOpen(openLogSegNo);
openLogOff = 0; openLogOff = 0;
} }
issue_xlog_fsync(openLogFile, openLogId, openLogSeg); issue_xlog_fsync(openLogFile, openLogSegNo);
} }
LogwrtResult.Flush = LogwrtResult.Write; LogwrtResult.Flush = LogwrtResult.Write;
} }
...@@ -2129,6 +2098,8 @@ XLogFlush(XLogRecPtr record) ...@@ -2129,6 +2098,8 @@ XLogFlush(XLogRecPtr record)
else else
{ {
WriteRqstPtr = XLogCtl->xlblocks[Insert->curridx]; WriteRqstPtr = XLogCtl->xlblocks[Insert->curridx];
if (WriteRqstPtr.xrecoff == 0)
WriteRqstPtr.xlogid--;
WriteRqstPtr.xrecoff -= freespace; WriteRqstPtr.xrecoff -= freespace;
} }
LWLockRelease(WALInsertLock); LWLockRelease(WALInsertLock);
...@@ -2240,7 +2211,7 @@ XLogBackgroundFlush(void) ...@@ -2240,7 +2211,7 @@ XLogBackgroundFlush(void)
{ {
if (openLogFile >= 0) if (openLogFile >= 0)
{ {
if (!XLByteInPrevSeg(LogwrtResult.Write, openLogId, openLogSeg)) if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo))
{ {
XLogFileClose(); XLogFileClose();
} }
...@@ -2372,19 +2343,17 @@ XLogNeedsFlush(XLogRecPtr record) ...@@ -2372,19 +2343,17 @@ XLogNeedsFlush(XLogRecPtr record)
* in a critical section. * in a critical section.
*/ */
int int
XLogFileInit(uint32 log, uint32 seg, XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
bool *use_existent, bool use_lock)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
char tmppath[MAXPGPATH]; char tmppath[MAXPGPATH];
char *zbuffer; char *zbuffer;
uint32 installed_log; XLogSegNo installed_segno;
uint32 installed_seg;
int max_advance; int max_advance;
int fd; int fd;
int nbytes; int nbytes;
XLogFilePath(path, ThisTimeLineID, log, seg); XLogFilePath(path, ThisTimeLineID, logsegno);
/* /*
* Try to use existent file (checkpoint maker may have created it already) * Try to use existent file (checkpoint maker may have created it already)
...@@ -2398,8 +2367,7 @@ XLogFileInit(uint32 log, uint32 seg, ...@@ -2398,8 +2367,7 @@ XLogFileInit(uint32 log, uint32 seg,
if (errno != ENOENT) if (errno != ENOENT)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file \"%s\" (log file %u, segment %u): %m", errmsg("could not open file \"%s\": %m", path)));
path, log, seg)));
} }
else else
return fd; return fd;
...@@ -2478,10 +2446,9 @@ XLogFileInit(uint32 log, uint32 seg, ...@@ -2478,10 +2446,9 @@ XLogFileInit(uint32 log, uint32 seg,
* has created the file while we were filling ours: if so, use ours to * has created the file while we were filling ours: if so, use ours to
* pre-create a future log segment. * pre-create a future log segment.
*/ */
installed_log = log; installed_segno = logsegno;
installed_seg = seg;
max_advance = XLOGfileslop; max_advance = XLOGfileslop;
if (!InstallXLogFileSegment(&installed_log, &installed_seg, tmppath, if (!InstallXLogFileSegment(&installed_segno, tmppath,
*use_existent, &max_advance, *use_existent, &max_advance,
use_lock)) use_lock))
{ {
...@@ -2502,8 +2469,7 @@ XLogFileInit(uint32 log, uint32 seg, ...@@ -2502,8 +2469,7 @@ XLogFileInit(uint32 log, uint32 seg,
if (fd < 0) if (fd < 0)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file \"%s\" (log file %u, segment %u): %m", errmsg("could not open file \"%s\": %m", path)));
path, log, seg)));
elog(DEBUG2, "done creating and filling new WAL file"); elog(DEBUG2, "done creating and filling new WAL file");
...@@ -2523,8 +2489,7 @@ XLogFileInit(uint32 log, uint32 seg, ...@@ -2523,8 +2489,7 @@ XLogFileInit(uint32 log, uint32 seg,
* emplacing a bogus file. * emplacing a bogus file.
*/ */
static void static void
XLogFileCopy(uint32 log, uint32 seg, XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno)
TimeLineID srcTLI, uint32 srclog, uint32 srcseg)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
char tmppath[MAXPGPATH]; char tmppath[MAXPGPATH];
...@@ -2536,7 +2501,7 @@ XLogFileCopy(uint32 log, uint32 seg, ...@@ -2536,7 +2501,7 @@ XLogFileCopy(uint32 log, uint32 seg,
/* /*
* Open the source file * Open the source file
*/ */
XLogFilePath(path, srcTLI, srclog, srcseg); XLogFilePath(path, srcTLI, srcsegno);
srcfd = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0); srcfd = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
if (srcfd < 0) if (srcfd < 0)
ereport(ERROR, ereport(ERROR,
...@@ -2607,7 +2572,7 @@ XLogFileCopy(uint32 log, uint32 seg, ...@@ -2607,7 +2572,7 @@ XLogFileCopy(uint32 log, uint32 seg,
/* /*
* Now move the segment into place with its final name. * Now move the segment into place with its final name.
*/ */
if (!InstallXLogFileSegment(&log, &seg, tmppath, false, NULL, false)) if (!InstallXLogFileSegment(&destsegno, tmppath, false, NULL, false))
elog(ERROR, "InstallXLogFileSegment should not have failed"); elog(ERROR, "InstallXLogFileSegment should not have failed");
} }
...@@ -2641,14 +2606,14 @@ XLogFileCopy(uint32 log, uint32 seg, ...@@ -2641,14 +2606,14 @@ XLogFileCopy(uint32 log, uint32 seg,
* file into place. * file into place.
*/ */
static bool static bool
InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath, InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
bool find_free, int *max_advance, bool find_free, int *max_advance,
bool use_lock) bool use_lock)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
struct stat stat_buf; struct stat stat_buf;
XLogFilePath(path, ThisTimeLineID, *log, *seg); XLogFilePath(path, ThisTimeLineID, *segno);
/* /*
* We want to be sure that only one process does this at a time. * We want to be sure that only one process does this at a time.
...@@ -2673,9 +2638,9 @@ InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath, ...@@ -2673,9 +2638,9 @@ InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath,
LWLockRelease(ControlFileLock); LWLockRelease(ControlFileLock);
return false; return false;
} }
NextLogSeg(*log, *seg); (*segno)++;
(*max_advance)--; (*max_advance)--;
XLogFilePath(path, ThisTimeLineID, *log, *seg); XLogFilePath(path, ThisTimeLineID, *segno);
} }
} }
...@@ -2691,8 +2656,8 @@ InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath, ...@@ -2691,8 +2656,8 @@ InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath,
LWLockRelease(ControlFileLock); LWLockRelease(ControlFileLock);
ereport(LOG, ereport(LOG,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not link file \"%s\" to \"%s\" (initialization of log file %u, segment %u): %m", errmsg("could not link file \"%s\" to \"%s\" (initialization of log file): %m",
tmppath, path, *log, *seg))); tmppath, path)));
return false; return false;
} }
unlink(tmppath); unlink(tmppath);
...@@ -2703,8 +2668,8 @@ InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath, ...@@ -2703,8 +2668,8 @@ InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath,
LWLockRelease(ControlFileLock); LWLockRelease(ControlFileLock);
ereport(LOG, ereport(LOG,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not rename file \"%s\" to \"%s\" (initialization of log file %u, segment %u): %m", errmsg("could not rename file \"%s\" to \"%s\" (initialization of log file): %m",
tmppath, path, *log, *seg))); tmppath, path)));
return false; return false;
} }
#endif #endif
...@@ -2719,20 +2684,19 @@ InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath, ...@@ -2719,20 +2684,19 @@ InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath,
* Open a pre-existing logfile segment for writing. * Open a pre-existing logfile segment for writing.
*/ */
int int
XLogFileOpen(uint32 log, uint32 seg) XLogFileOpen(XLogSegNo segno)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
int fd; int fd;
XLogFilePath(path, ThisTimeLineID, log, seg); XLogFilePath(path, ThisTimeLineID, segno);
fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method), fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
S_IRUSR | S_IWUSR); S_IRUSR | S_IWUSR);
if (fd < 0) if (fd < 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file \"%s\" (log file %u, segment %u): %m", errmsg("could not open xlog file \"%s\": %m", path)));
path, log, seg)));
return fd; return fd;
} }
...@@ -2744,7 +2708,7 @@ XLogFileOpen(uint32 log, uint32 seg) ...@@ -2744,7 +2708,7 @@ XLogFileOpen(uint32 log, uint32 seg)
* Otherwise, it's assumed to be already available in pg_xlog. * Otherwise, it's assumed to be already available in pg_xlog.
*/ */
static int static int
XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli, XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
int source, bool notfoundOk) int source, bool notfoundOk)
{ {
char xlogfname[MAXFNAMELEN]; char xlogfname[MAXFNAMELEN];
...@@ -2752,7 +2716,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli, ...@@ -2752,7 +2716,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
char path[MAXPGPATH]; char path[MAXPGPATH];
int fd; int fd;
XLogFileName(xlogfname, tli, log, seg); XLogFileName(xlogfname, tli, segno);
switch (source) switch (source)
{ {
...@@ -2771,7 +2735,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli, ...@@ -2771,7 +2735,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
case XLOG_FROM_PG_XLOG: case XLOG_FROM_PG_XLOG:
case XLOG_FROM_STREAM: case XLOG_FROM_STREAM:
XLogFilePath(path, tli, log, seg); XLogFilePath(path, tli, segno);
restoredFromArchive = false; restoredFromArchive = false;
break; break;
...@@ -2792,7 +2756,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli, ...@@ -2792,7 +2756,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
bool reload = false; bool reload = false;
struct stat statbuf; struct stat statbuf;
XLogFilePath(xlogfpath, tli, log, seg); XLogFilePath(xlogfpath, tli, segno);
if (stat(xlogfpath, &statbuf) == 0) if (stat(xlogfpath, &statbuf) == 0)
{ {
if (unlink(xlogfpath) != 0) if (unlink(xlogfpath) != 0)
...@@ -2821,8 +2785,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli, ...@@ -2821,8 +2785,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
* shmem. It's used as current standby flush position, and cascading * shmem. It's used as current standby flush position, and cascading
* walsenders try to send WAL records up to this location. * walsenders try to send WAL records up to this location.
*/ */
endptr.xlogid = log; XLogSegNoOffsetToRecPtr(segno, 0, endptr);
endptr.xrecoff = seg * XLogSegSize;
XLByteAdvance(endptr, XLogSegSize); XLByteAdvance(endptr, XLogSegSize);
SpinLockAcquire(&xlogctl->info_lck); SpinLockAcquire(&xlogctl->info_lck);
...@@ -2857,8 +2820,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli, ...@@ -2857,8 +2820,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
if (errno != ENOENT || !notfoundOk) /* unexpected failure? */ if (errno != ENOENT || !notfoundOk) /* unexpected failure? */
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file \"%s\" (log file %u, segment %u): %m", errmsg("could not open file \"%s\": %m", path)));
path, log, seg)));
return -1; return -1;
} }
...@@ -2868,7 +2830,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli, ...@@ -2868,7 +2830,7 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
* This version searches for the segment with any TLI listed in expectedTLIs. * This version searches for the segment with any TLI listed in expectedTLIs.
*/ */
static int static int
XLogFileReadAnyTLI(uint32 log, uint32 seg, int emode, int sources) XLogFileReadAnyTLI(XLogSegNo segno, int emode, int sources)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
ListCell *cell; ListCell *cell;
...@@ -2893,7 +2855,7 @@ XLogFileReadAnyTLI(uint32 log, uint32 seg, int emode, int sources) ...@@ -2893,7 +2855,7 @@ XLogFileReadAnyTLI(uint32 log, uint32 seg, int emode, int sources)
if (sources & XLOG_FROM_ARCHIVE) if (sources & XLOG_FROM_ARCHIVE)
{ {
fd = XLogFileRead(log, seg, emode, tli, XLOG_FROM_ARCHIVE, true); fd = XLogFileRead(segno, emode, tli, XLOG_FROM_ARCHIVE, true);
if (fd != -1) if (fd != -1)
{ {
elog(DEBUG1, "got WAL segment from archive"); elog(DEBUG1, "got WAL segment from archive");
...@@ -2903,19 +2865,18 @@ XLogFileReadAnyTLI(uint32 log, uint32 seg, int emode, int sources) ...@@ -2903,19 +2865,18 @@ XLogFileReadAnyTLI(uint32 log, uint32 seg, int emode, int sources)
if (sources & XLOG_FROM_PG_XLOG) if (sources & XLOG_FROM_PG_XLOG)
{ {
fd = XLogFileRead(log, seg, emode, tli, XLOG_FROM_PG_XLOG, true); fd = XLogFileRead(segno, emode, tli, XLOG_FROM_PG_XLOG, true);
if (fd != -1) if (fd != -1)
return fd; return fd;
} }
} }
/* Couldn't find it. For simplicity, complain about front timeline */ /* Couldn't find it. For simplicity, complain about front timeline */
XLogFilePath(path, recoveryTargetTLI, log, seg); XLogFilePath(path, recoveryTargetTLI, segno);
errno = ENOENT; errno = ENOENT;
ereport(emode, ereport(emode,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file \"%s\" (log file %u, segment %u): %m", errmsg("could not open file \"%s\": %m", path)));
path, log, seg)));
return -1; return -1;
} }
...@@ -2941,8 +2902,8 @@ XLogFileClose(void) ...@@ -2941,8 +2902,8 @@ XLogFileClose(void)
if (close(openLogFile)) if (close(openLogFile))
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not close log file %u, segment %u: %m", errmsg("could not close log file %s: %m",
openLogId, openLogSeg))); XLogFileNameP(ThisTimeLineID, openLogSegNo))));
openLogFile = -1; openLogFile = -1;
} }
...@@ -2973,8 +2934,7 @@ RestoreArchivedFile(char *path, const char *xlogfname, ...@@ -2973,8 +2934,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
int rc; int rc;
bool signaled; bool signaled;
struct stat stat_buf; struct stat stat_buf;
uint32 restartLog; XLogSegNo restartSegNo;
uint32 restartSeg;
/* In standby mode, restore_command might not be supplied */ /* In standby mode, restore_command might not be supplied */
if (recoveryRestoreCommand == NULL) if (recoveryRestoreCommand == NULL)
...@@ -3043,16 +3003,15 @@ RestoreArchivedFile(char *path, const char *xlogfname, ...@@ -3043,16 +3003,15 @@ RestoreArchivedFile(char *path, const char *xlogfname,
*/ */
if (InRedo) if (InRedo)
{ {
XLByteToSeg(ControlFile->checkPointCopy.redo, XLByteToSeg(ControlFile->checkPointCopy.redo, restartSegNo);
restartLog, restartSeg);
XLogFileName(lastRestartPointFname, XLogFileName(lastRestartPointFname,
ControlFile->checkPointCopy.ThisTimeLineID, ControlFile->checkPointCopy.ThisTimeLineID,
restartLog, restartSeg); restartSegNo);
/* we shouldn't need anything earlier than last restart point */ /* we shouldn't need anything earlier than last restart point */
Assert(strcmp(lastRestartPointFname, xlogfname) <= 0); Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
} }
else else
XLogFileName(lastRestartPointFname, 0, 0, 0); XLogFileName(lastRestartPointFname, 0, 0L);
/* /*
* construct the command to be executed * construct the command to be executed
...@@ -3247,8 +3206,7 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal) ...@@ -3247,8 +3206,7 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
const char *sp; const char *sp;
int rc; int rc;
bool signaled; bool signaled;
uint32 restartLog; XLogSegNo restartSegNo;
uint32 restartSeg;
Assert(command && commandName); Assert(command && commandName);
...@@ -3258,11 +3216,10 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal) ...@@ -3258,11 +3216,10 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
* archive, though there is no requirement to do so. * archive, though there is no requirement to do so.
*/ */
LWLockAcquire(ControlFileLock, LW_SHARED); LWLockAcquire(ControlFileLock, LW_SHARED);
XLByteToSeg(ControlFile->checkPointCopy.redo, XLByteToSeg(ControlFile->checkPointCopy.redo, restartSegNo);
restartLog, restartSeg);
XLogFileName(lastRestartPointFname, XLogFileName(lastRestartPointFname,
ControlFile->checkPointCopy.ThisTimeLineID, ControlFile->checkPointCopy.ThisTimeLineID,
restartLog, restartSeg); restartSegNo);
LWLockRelease(ControlFileLock); LWLockRelease(ControlFileLock);
/* /*
...@@ -3343,18 +3300,17 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal) ...@@ -3343,18 +3300,17 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
static void static void
PreallocXlogFiles(XLogRecPtr endptr) PreallocXlogFiles(XLogRecPtr endptr)
{ {
uint32 _logId; XLogSegNo _logSegNo;
uint32 _logSeg;
int lf; int lf;
bool use_existent; bool use_existent;
XLByteToPrevSeg(endptr, _logId, _logSeg); XLByteToPrevSeg(endptr, _logSegNo);
if ((endptr.xrecoff - 1) % XLogSegSize >= if ((endptr.xrecoff - 1) % XLogSegSize >=
(uint32) (0.75 * XLogSegSize)) (uint32) (0.75 * XLogSegSize))
{ {
NextLogSeg(_logId, _logSeg); _logSegNo++;
use_existent = true; use_existent = true;
lf = XLogFileInit(_logId, _logSeg, &use_existent, true); lf = XLogFileInit(_logSegNo, &use_existent, true);
close(lf); close(lf);
if (!use_existent) if (!use_existent)
CheckpointStats.ckpt_segs_added++; CheckpointStats.ckpt_segs_added++;
...@@ -3366,14 +3322,13 @@ PreallocXlogFiles(XLogRecPtr endptr) ...@@ -3366,14 +3322,13 @@ PreallocXlogFiles(XLogRecPtr endptr)
* Returns 0/0 if no WAL segments have been removed since startup. * Returns 0/0 if no WAL segments have been removed since startup.
*/ */
void void
XLogGetLastRemoved(uint32 *log, uint32 *seg) XLogGetLastRemoved(XLogSegNo *segno)
{ {
/* use volatile pointer to prevent code rearrangement */ /* use volatile pointer to prevent code rearrangement */
volatile XLogCtlData *xlogctl = XLogCtl; volatile XLogCtlData *xlogctl = XLogCtl;
SpinLockAcquire(&xlogctl->info_lck); SpinLockAcquire(&xlogctl->info_lck);
*log = xlogctl->lastRemovedLog; *segno = xlogctl->lastRemovedSegNo;
*seg = xlogctl->lastRemovedSeg;
SpinLockRelease(&xlogctl->info_lck); SpinLockRelease(&xlogctl->info_lck);
} }
...@@ -3386,19 +3341,14 @@ UpdateLastRemovedPtr(char *filename) ...@@ -3386,19 +3341,14 @@ UpdateLastRemovedPtr(char *filename)
{ {
/* use volatile pointer to prevent code rearrangement */ /* use volatile pointer to prevent code rearrangement */
volatile XLogCtlData *xlogctl = XLogCtl; volatile XLogCtlData *xlogctl = XLogCtl;
uint32 tli, uint32 tli;
log, XLogSegNo segno;
seg;
XLogFromFileName(filename, &tli, &log, &seg); XLogFromFileName(filename, &tli, &segno);
SpinLockAcquire(&xlogctl->info_lck); SpinLockAcquire(&xlogctl->info_lck);
if (log > xlogctl->lastRemovedLog || if (segno > xlogctl->lastRemovedSegNo)
(log == xlogctl->lastRemovedLog && seg > xlogctl->lastRemovedSeg)) xlogctl->lastRemovedSegNo = segno;
{
xlogctl->lastRemovedLog = log;
xlogctl->lastRemovedSeg = seg;
}
SpinLockRelease(&xlogctl->info_lck); SpinLockRelease(&xlogctl->info_lck);
} }
...@@ -3409,10 +3359,9 @@ UpdateLastRemovedPtr(char *filename) ...@@ -3409,10 +3359,9 @@ UpdateLastRemovedPtr(char *filename)
* whether we want to recycle rather than delete no-longer-wanted log files. * whether we want to recycle rather than delete no-longer-wanted log files.
*/ */
static void static void
RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr) RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr endptr)
{ {
uint32 endlogId; XLogSegNo endlogSegNo;
uint32 endlogSeg;
int max_advance; int max_advance;
DIR *xldir; DIR *xldir;
struct dirent *xlde; struct dirent *xlde;
...@@ -3428,7 +3377,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr) ...@@ -3428,7 +3377,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
* Initialize info about where to try to recycle to. We allow recycling * Initialize info about where to try to recycle to. We allow recycling
* segments up to XLOGfileslop segments beyond the current XLOG location. * segments up to XLOGfileslop segments beyond the current XLOG location.
*/ */
XLByteToPrevSeg(endptr, endlogId, endlogSeg); XLByteToPrevSeg(endptr, endlogSegNo);
max_advance = XLOGfileslop; max_advance = XLOGfileslop;
xldir = AllocateDir(XLOGDIR); xldir = AllocateDir(XLOGDIR);
...@@ -3438,7 +3387,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr) ...@@ -3438,7 +3387,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
errmsg("could not open transaction log directory \"%s\": %m", errmsg("could not open transaction log directory \"%s\": %m",
XLOGDIR))); XLOGDIR)));
XLogFileName(lastoff, ThisTimeLineID, log, seg); XLogFileName(lastoff, ThisTimeLineID, segno);
elog(DEBUG2, "attempting to remove WAL segments older than log file %s", elog(DEBUG2, "attempting to remove WAL segments older than log file %s",
lastoff); lastoff);
...@@ -3474,7 +3423,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr) ...@@ -3474,7 +3423,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
* separate archive directory. * separate archive directory.
*/ */
if (lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) && if (lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) &&
InstallXLogFileSegment(&endlogId, &endlogSeg, path, InstallXLogFileSegment(&endlogSegNo, path,
true, &max_advance, true)) true, &max_advance, true))
{ {
ereport(DEBUG2, ereport(DEBUG2,
...@@ -3484,7 +3433,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr) ...@@ -3484,7 +3433,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
/* Needn't recheck that slot on future iterations */ /* Needn't recheck that slot on future iterations */
if (max_advance > 0) if (max_advance > 0)
{ {
NextLogSeg(endlogId, endlogSeg); endlogSegNo++;
max_advance--; max_advance--;
} }
} }
...@@ -3823,13 +3772,6 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt) ...@@ -3823,13 +3772,6 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
if (XLOG_BLCKSZ - (RecPtr->xrecoff % XLOG_BLCKSZ) < SizeOfXLogRecord) if (XLOG_BLCKSZ - (RecPtr->xrecoff % XLOG_BLCKSZ) < SizeOfXLogRecord)
NextLogPage(*RecPtr); NextLogPage(*RecPtr);
/* Check for crossing of xlog segment boundary */
if (RecPtr->xrecoff >= XLogFileSize)
{
(RecPtr->xlogid)++;
RecPtr->xrecoff = 0;
}
/* /*
* If at page start, we must skip over the page header. But we can't * If at page start, we must skip over the page header. But we can't
* do that until we've read in the page, since the header size is * do that until we've read in the page, since the header size is
...@@ -4013,12 +3955,7 @@ retry: ...@@ -4013,12 +3955,7 @@ retry:
for (;;) for (;;)
{ {
/* Calculate pointer to beginning of next page */ /* Calculate pointer to beginning of next page */
pagelsn.xrecoff += XLOG_BLCKSZ; XLByteAdvance(pagelsn, XLOG_BLCKSZ);
if (pagelsn.xrecoff >= XLogFileSize)
{
(pagelsn.xlogid)++;
pagelsn.xrecoff = 0;
}
/* Wait for the next page to become available */ /* Wait for the next page to become available */
if (!XLogPageRead(&pagelsn, emode, false, false)) if (!XLogPageRead(&pagelsn, emode, false, false))
return NULL; return NULL;
...@@ -4027,8 +3964,9 @@ retry: ...@@ -4027,8 +3964,9 @@ retry:
if (!(((XLogPageHeader) readBuf)->xlp_info & XLP_FIRST_IS_CONTRECORD)) if (!(((XLogPageHeader) readBuf)->xlp_info & XLP_FIRST_IS_CONTRECORD))
{ {
ereport(emode_for_corrupt_record(emode, *RecPtr), ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("there is no contrecord flag in log file %u, segment %u, offset %u", (errmsg("there is no contrecord flag in log segment %s, offset %u",
readId, readSeg, readOff))); XLogFileNameP(curFileTLI, readSegNo),
readOff)));
goto next_record_is_invalid; goto next_record_is_invalid;
} }
pageHeaderSize = XLogPageHeaderSize((XLogPageHeader) readBuf); pageHeaderSize = XLogPageHeaderSize((XLogPageHeader) readBuf);
...@@ -4036,10 +3974,13 @@ retry: ...@@ -4036,10 +3974,13 @@ retry:
if (contrecord->xl_rem_len == 0 || if (contrecord->xl_rem_len == 0 ||
total_len != (contrecord->xl_rem_len + gotlen)) total_len != (contrecord->xl_rem_len + gotlen))
{ {
char fname[MAXFNAMELEN];
XLogFileName(fname, curFileTLI, readSegNo);
ereport(emode_for_corrupt_record(emode, *RecPtr), ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("invalid contrecord length %u in log file %u, segment %u, offset %u", (errmsg("invalid contrecord length %u in log segment %s, offset %u",
contrecord->xl_rem_len, contrecord->xl_rem_len,
readId, readSeg, readOff))); XLogFileNameP(curFileTLI, readSegNo),
readOff)));
goto next_record_is_invalid; goto next_record_is_invalid;
} }
len = XLOG_BLCKSZ - pageHeaderSize - SizeOfXLogContRecord; len = XLOG_BLCKSZ - pageHeaderSize - SizeOfXLogContRecord;
...@@ -4057,11 +3998,11 @@ retry: ...@@ -4057,11 +3998,11 @@ retry:
if (!RecordIsValid(record, *RecPtr, emode)) if (!RecordIsValid(record, *RecPtr, emode))
goto next_record_is_invalid; goto next_record_is_invalid;
pageHeaderSize = XLogPageHeaderSize((XLogPageHeader) readBuf); pageHeaderSize = XLogPageHeaderSize((XLogPageHeader) readBuf);
EndRecPtr.xlogid = readId; XLogSegNoOffsetToRecPtr(
EndRecPtr.xrecoff = readSeg * XLogSegSize + readOff + readSegNo,
pageHeaderSize + readOff + pageHeaderSize +
MAXALIGN(SizeOfXLogContRecord + contrecord->xl_rem_len); MAXALIGN(SizeOfXLogContRecord + contrecord->xl_rem_len),
EndRecPtr);
ReadRecPtr = *RecPtr; ReadRecPtr = *RecPtr;
/* needn't worry about XLOG SWITCH, it can't cross page boundaries */ /* needn't worry about XLOG SWITCH, it can't cross page boundaries */
return record; return record;
...@@ -4121,21 +4062,24 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode) ...@@ -4121,21 +4062,24 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
{ {
XLogRecPtr recaddr; XLogRecPtr recaddr;
recaddr.xlogid = readId; XLogSegNoOffsetToRecPtr(readSegNo, readOff, recaddr);
recaddr.xrecoff = readSeg * XLogSegSize + readOff;
if (hdr->xlp_magic != XLOG_PAGE_MAGIC) if (hdr->xlp_magic != XLOG_PAGE_MAGIC)
{ {
ereport(emode_for_corrupt_record(emode, recaddr), ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("invalid magic number %04X in log file %u, segment %u, offset %u", (errmsg("invalid magic number %04X in log segment %s, offset %u",
hdr->xlp_magic, readId, readSeg, readOff))); hdr->xlp_magic,
XLogFileNameP(curFileTLI, readSegNo),
readOff)));
return false; return false;
} }
if ((hdr->xlp_info & ~XLP_ALL_FLAGS) != 0) if ((hdr->xlp_info & ~XLP_ALL_FLAGS) != 0)
{ {
ereport(emode_for_corrupt_record(emode, recaddr), ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("invalid info bits %04X in log file %u, segment %u, offset %u", (errmsg("invalid info bits %04X in log segment %s, offset %u",
hdr->xlp_info, readId, readSeg, readOff))); hdr->xlp_info,
XLogFileNameP(curFileTLI, readSegNo),
readOff)));
return false; return false;
} }
if (hdr->xlp_info & XLP_LONG_HEADER) if (hdr->xlp_info & XLP_LONG_HEADER)
...@@ -4180,17 +4124,20 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode) ...@@ -4180,17 +4124,20 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
{ {
/* hmm, first page of file doesn't have a long header? */ /* hmm, first page of file doesn't have a long header? */
ereport(emode_for_corrupt_record(emode, recaddr), ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("invalid info bits %04X in log file %u, segment %u, offset %u", (errmsg("invalid info bits %04X in log segment %s, offset %u",
hdr->xlp_info, readId, readSeg, readOff))); hdr->xlp_info,
XLogFileNameP(curFileTLI, readSegNo),
readOff)));
return false; return false;
} }
if (!XLByteEQ(hdr->xlp_pageaddr, recaddr)) if (!XLByteEQ(hdr->xlp_pageaddr, recaddr))
{ {
ereport(emode_for_corrupt_record(emode, recaddr), ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("unexpected pageaddr %X/%X in log file %u, segment %u, offset %u", (errmsg("unexpected pageaddr %X/%X in log segment %s, offset %u",
hdr->xlp_pageaddr.xlogid, hdr->xlp_pageaddr.xrecoff, hdr->xlp_pageaddr.xlogid, hdr->xlp_pageaddr.xrecoff,
readId, readSeg, readOff))); XLogFileNameP(curFileTLI, readSegNo),
readOff)));
return false; return false;
} }
...@@ -4200,9 +4147,10 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode) ...@@ -4200,9 +4147,10 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
if (!list_member_int(expectedTLIs, (int) hdr->xlp_tli)) if (!list_member_int(expectedTLIs, (int) hdr->xlp_tli))
{ {
ereport(emode_for_corrupt_record(emode, recaddr), ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("unexpected timeline ID %u in log file %u, segment %u, offset %u", (errmsg("unexpected timeline ID %u in log segment %s, offset %u",
hdr->xlp_tli, hdr->xlp_tli,
readId, readSeg, readOff))); XLogFileNameP(curFileTLI, readSegNo),
readOff)));
return false; return false;
} }
...@@ -4218,9 +4166,10 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode) ...@@ -4218,9 +4166,10 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
if (hdr->xlp_tli < lastPageTLI) if (hdr->xlp_tli < lastPageTLI)
{ {
ereport(emode_for_corrupt_record(emode, recaddr), ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("out-of-sequence timeline ID %u (after %u) in log file %u, segment %u, offset %u", (errmsg("out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u",
hdr->xlp_tli, lastPageTLI, hdr->xlp_tli, lastPageTLI,
readId, readSeg, readOff))); XLogFileNameP(curFileTLI, readSegNo),
readOff)));
return false; return false;
} }
lastPageTLI = hdr->xlp_tli; lastPageTLI = hdr->xlp_tli;
...@@ -4467,7 +4416,7 @@ findNewestTimeLine(TimeLineID startTLI) ...@@ -4467,7 +4416,7 @@ findNewestTimeLine(TimeLineID startTLI)
*/ */
static void static void
writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg) TimeLineID endTLI, XLogSegNo endLogSegNo)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
char tmppath[MAXPGPATH]; char tmppath[MAXPGPATH];
...@@ -4557,7 +4506,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, ...@@ -4557,7 +4506,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
* If we did have a parent file, insert an extra newline just in case the * If we did have a parent file, insert an extra newline just in case the
* parent file failed to end with one. * parent file failed to end with one.
*/ */
XLogFileName(xlogfname, endTLI, endLogId, endLogSeg); XLogFileName(xlogfname, endTLI, endLogSegNo);
/* /*
* Write comment to history file to explain why and where timeline * Write comment to history file to explain why and where timeline
...@@ -5243,7 +5192,7 @@ BootStrapXLOG(void) ...@@ -5243,7 +5192,7 @@ BootStrapXLOG(void)
/* Create first XLOG segment file */ /* Create first XLOG segment file */
use_existent = false; use_existent = false;
openLogFile = XLogFileInit(0, 1, &use_existent, false); openLogFile = XLogFileInit(1, &use_existent, false);
/* Write the first page with the initial record */ /* Write the first page with the initial record */
errno = 0; errno = 0;
...@@ -5554,7 +5503,7 @@ readRecoveryCommandFile(void) ...@@ -5554,7 +5503,7 @@ readRecoveryCommandFile(void)
* Exit archive-recovery state * Exit archive-recovery state
*/ */
static void static void
exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg) exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
{ {
char recoveryPath[MAXPGPATH]; char recoveryPath[MAXPGPATH];
char xlogpath[MAXPGPATH]; char xlogpath[MAXPGPATH];
...@@ -5590,12 +5539,11 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg) ...@@ -5590,12 +5539,11 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
*/ */
if (endTLI != ThisTimeLineID) if (endTLI != ThisTimeLineID)
{ {
XLogFileCopy(endLogId, endLogSeg, XLogFileCopy(endLogSegNo, endTLI, endLogSegNo);
endTLI, endLogId, endLogSeg);
if (XLogArchivingActive()) if (XLogArchivingActive())
{ {
XLogFileName(xlogpath, endTLI, endLogId, endLogSeg); XLogFileName(xlogpath, endTLI, endLogSegNo);
XLogArchiveNotify(xlogpath); XLogArchiveNotify(xlogpath);
} }
} }
...@@ -5604,7 +5552,7 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg) ...@@ -5604,7 +5552,7 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
* Let's just make real sure there are not .ready or .done flags posted * Let's just make real sure there are not .ready or .done flags posted
* for the new segment. * for the new segment.
*/ */
XLogFileName(xlogpath, ThisTimeLineID, endLogId, endLogSeg); XLogFileName(xlogpath, ThisTimeLineID, endLogSegNo);
XLogArchiveCleanup(xlogpath); XLogArchiveCleanup(xlogpath);
/* /*
...@@ -6004,8 +5952,7 @@ StartupXLOG(void) ...@@ -6004,8 +5952,7 @@ StartupXLOG(void)
XLogRecPtr RecPtr, XLogRecPtr RecPtr,
checkPointLoc, checkPointLoc,
EndOfLog; EndOfLog;
uint32 endLogId; XLogSegNo endLogSegNo;
uint32 endLogSeg;
XLogRecord *record; XLogRecord *record;
uint32 freespace; uint32 freespace;
TransactionId oldestActiveXID; TransactionId oldestActiveXID;
...@@ -6732,7 +6679,7 @@ StartupXLOG(void) ...@@ -6732,7 +6679,7 @@ StartupXLOG(void)
*/ */
record = ReadRecord(&LastRec, PANIC, false); record = ReadRecord(&LastRec, PANIC, false);
EndOfLog = EndRecPtr; EndOfLog = EndRecPtr;
XLByteToPrevSeg(EndOfLog, endLogId, endLogSeg); XLByteToPrevSeg(EndOfLog, endLogSegNo);
/* /*
* Complain if we did not roll forward far enough to render the backup * Complain if we did not roll forward far enough to render the backup
...@@ -6797,7 +6744,7 @@ StartupXLOG(void) ...@@ -6797,7 +6744,7 @@ StartupXLOG(void)
ereport(LOG, ereport(LOG,
(errmsg("selected new timeline ID: %u", ThisTimeLineID))); (errmsg("selected new timeline ID: %u", ThisTimeLineID)));
writeTimeLineHistory(ThisTimeLineID, recoveryTargetTLI, writeTimeLineHistory(ThisTimeLineID, recoveryTargetTLI,
curFileTLI, endLogId, endLogSeg); curFileTLI, endLogSegNo);
} }
/* Save the selected TimeLineID in shared memory, too */ /* Save the selected TimeLineID in shared memory, too */
...@@ -6810,20 +6757,19 @@ StartupXLOG(void) ...@@ -6810,20 +6757,19 @@ StartupXLOG(void)
* we will use that below.) * we will use that below.)
*/ */
if (InArchiveRecovery) if (InArchiveRecovery)
exitArchiveRecovery(curFileTLI, endLogId, endLogSeg); exitArchiveRecovery(curFileTLI, endLogSegNo);
/* /*
* Prepare to write WAL starting at EndOfLog position, and init xlog * Prepare to write WAL starting at EndOfLog position, and init xlog
* buffer cache using the block containing the last record from the * buffer cache using the block containing the last record from the
* previous incarnation. * previous incarnation.
*/ */
openLogId = endLogId; openLogSegNo = endLogSegNo;
openLogSeg = endLogSeg; openLogFile = XLogFileOpen(openLogSegNo);
openLogFile = XLogFileOpen(openLogId, openLogSeg);
openLogOff = 0; openLogOff = 0;
Insert = &XLogCtl->Insert; Insert = &XLogCtl->Insert;
Insert->PrevRecord = LastRec; Insert->PrevRecord = LastRec;
XLogCtl->xlblocks[0].xlogid = openLogId; XLogCtl->xlblocks[0].xlogid = (openLogSegNo * XLOG_SEG_SIZE) >> 32;
XLogCtl->xlblocks[0].xrecoff = XLogCtl->xlblocks[0].xrecoff =
((EndOfLog.xrecoff - 1) / XLOG_BLCKSZ + 1) * XLOG_BLCKSZ; ((EndOfLog.xrecoff - 1) / XLOG_BLCKSZ + 1) * XLOG_BLCKSZ;
...@@ -7644,8 +7590,7 @@ CreateCheckPoint(int flags) ...@@ -7644,8 +7590,7 @@ CreateCheckPoint(int flags)
XLogCtlInsert *Insert = &XLogCtl->Insert; XLogCtlInsert *Insert = &XLogCtl->Insert;
XLogRecData rdata; XLogRecData rdata;
uint32 freespace; uint32 freespace;
uint32 _logId; XLogSegNo _logSegNo;
uint32 _logSeg;
TransactionId *inCommitXids; TransactionId *inCommitXids;
int nInCommit; int nInCommit;
...@@ -7948,7 +7893,7 @@ CreateCheckPoint(int flags) ...@@ -7948,7 +7893,7 @@ CreateCheckPoint(int flags)
* Select point at which we can truncate the log, which we base on the * Select point at which we can truncate the log, which we base on the
* prior checkpoint's earliest info. * prior checkpoint's earliest info.
*/ */
XLByteToSeg(ControlFile->checkPointCopy.redo, _logId, _logSeg); XLByteToSeg(ControlFile->checkPointCopy.redo, _logSegNo);
/* /*
* Update the control file. * Update the control file.
...@@ -7991,11 +7936,11 @@ CreateCheckPoint(int flags) ...@@ -7991,11 +7936,11 @@ CreateCheckPoint(int flags)
* Delete old log files (those no longer needed even for previous * Delete old log files (those no longer needed even for previous
* checkpoint or the standbys in XLOG streaming). * checkpoint or the standbys in XLOG streaming).
*/ */
if (_logId || _logSeg) if (_logSegNo)
{ {
KeepLogSeg(recptr, &_logId, &_logSeg); KeepLogSeg(recptr, &_logSegNo);
PrevLogSeg(_logId, _logSeg); _logSegNo--;
RemoveOldXlogFiles(_logId, _logSeg, recptr); RemoveOldXlogFiles(_logSegNo, recptr);
} }
/* /*
...@@ -8127,8 +8072,7 @@ CreateRestartPoint(int flags) ...@@ -8127,8 +8072,7 @@ CreateRestartPoint(int flags)
{ {
XLogRecPtr lastCheckPointRecPtr; XLogRecPtr lastCheckPointRecPtr;
CheckPoint lastCheckPoint; CheckPoint lastCheckPoint;
uint32 _logId; XLogSegNo _logSegNo;
uint32 _logSeg;
TimestampTz xtime; TimestampTz xtime;
/* use volatile pointer to prevent code rearrangement */ /* use volatile pointer to prevent code rearrangement */
...@@ -8226,7 +8170,7 @@ CreateRestartPoint(int flags) ...@@ -8226,7 +8170,7 @@ CreateRestartPoint(int flags)
* Select point at which we can truncate the xlog, which we base on the * Select point at which we can truncate the xlog, which we base on the
* prior checkpoint's earliest info. * prior checkpoint's earliest info.
*/ */
XLByteToSeg(ControlFile->checkPointCopy.redo, _logId, _logSeg); XLByteToSeg(ControlFile->checkPointCopy.redo, _logSegNo);
/* /*
* Update pg_control, using current time. Check that it still shows * Update pg_control, using current time. Check that it still shows
...@@ -8253,16 +8197,16 @@ CreateRestartPoint(int flags) ...@@ -8253,16 +8197,16 @@ CreateRestartPoint(int flags)
* checkpoint/restartpoint) to prevent the disk holding the xlog from * checkpoint/restartpoint) to prevent the disk holding the xlog from
* growing full. * growing full.
*/ */
if (_logId || _logSeg) if (_logSegNo)
{ {
XLogRecPtr endptr; XLogRecPtr endptr;
/* Get the current (or recent) end of xlog */ /* Get the current (or recent) end of xlog */
endptr = GetStandbyFlushRecPtr(); endptr = GetStandbyFlushRecPtr();
KeepLogSeg(endptr, &_logId, &_logSeg); KeepLogSeg(endptr, &_logSegNo);
PrevLogSeg(_logId, _logSeg); _logSegNo--;
RemoveOldXlogFiles(_logId, _logSeg, endptr); RemoveOldXlogFiles(_logSegNo, endptr);
/* /*
* Make more log segments if needed. (Do this after recycling old log * Make more log segments if needed. (Do this after recycling old log
...@@ -8310,42 +8254,24 @@ CreateRestartPoint(int flags) ...@@ -8310,42 +8254,24 @@ CreateRestartPoint(int flags)
* the given xlog location, recptr. * the given xlog location, recptr.
*/ */
static void static void
KeepLogSeg(XLogRecPtr recptr, uint32 *logId, uint32 *logSeg) KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
{ {
uint32 log; XLogSegNo segno;
uint32 seg;
int d_log;
int d_seg;
if (wal_keep_segments == 0) if (wal_keep_segments == 0)
return; return;
XLByteToSeg(recptr, log, seg); XLByteToSeg(recptr, segno);
d_seg = wal_keep_segments % XLogSegsPerFile; /* avoid underflow, don't go below 1 */
d_log = wal_keep_segments / XLogSegsPerFile; if (segno <= wal_keep_segments)
if (seg < d_seg) segno = 1;
{
d_log += 1;
seg = seg - d_seg + XLogSegsPerFile;
}
else
seg = seg - d_seg;
/* avoid underflow, don't go below (0,1) */
if (log < d_log || (log == d_log && seg == 0))
{
log = 0;
seg = 1;
}
else else
log = log - d_log; segno = *logSegNo - wal_keep_segments;
/* don't delete WAL segments newer than the calculated segment */ /* don't delete WAL segments newer than the calculated segment */
if (log < *logId || (log == *logId && seg < *logSeg)) if (segno < *logSegNo)
{ *logSegNo = segno;
*logId = log;
*logSeg = seg;
}
} }
/* /*
...@@ -9010,8 +8936,8 @@ assign_xlog_sync_method(int new_sync_method, void *extra) ...@@ -9010,8 +8936,8 @@ assign_xlog_sync_method(int new_sync_method, void *extra)
if (pg_fsync(openLogFile) != 0) if (pg_fsync(openLogFile) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not fsync log file %u, segment %u: %m", errmsg("could not fsync log segment %s: %m",
openLogId, openLogSeg))); XLogFileNameP(curFileTLI, readSegNo))));
if (get_sync_bit(sync_method) != get_sync_bit(new_sync_method)) if (get_sync_bit(sync_method) != get_sync_bit(new_sync_method))
XLogFileClose(); XLogFileClose();
} }
...@@ -9026,7 +8952,7 @@ assign_xlog_sync_method(int new_sync_method, void *extra) ...@@ -9026,7 +8952,7 @@ assign_xlog_sync_method(int new_sync_method, void *extra)
* 'log' and 'seg' are for error reporting purposes. * 'log' and 'seg' are for error reporting purposes.
*/ */
void void
issue_xlog_fsync(int fd, uint32 log, uint32 seg) issue_xlog_fsync(int fd, XLogSegNo segno)
{ {
switch (sync_method) switch (sync_method)
{ {
...@@ -9034,16 +8960,16 @@ issue_xlog_fsync(int fd, uint32 log, uint32 seg) ...@@ -9034,16 +8960,16 @@ issue_xlog_fsync(int fd, uint32 log, uint32 seg)
if (pg_fsync_no_writethrough(fd) != 0) if (pg_fsync_no_writethrough(fd) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not fsync log file %u, segment %u: %m", errmsg("could not fsync log file %s: %m",
log, seg))); XLogFileNameP(ThisTimeLineID, openLogSegNo))));
break; break;
#ifdef HAVE_FSYNC_WRITETHROUGH #ifdef HAVE_FSYNC_WRITETHROUGH
case SYNC_METHOD_FSYNC_WRITETHROUGH: case SYNC_METHOD_FSYNC_WRITETHROUGH:
if (pg_fsync_writethrough(fd) != 0) if (pg_fsync_writethrough(fd) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not fsync write-through log file %u, segment %u: %m", errmsg("could not fsync write-through log file %s: %m",
log, seg))); XLogFileNameP(ThisTimeLineID, openLogSegNo)))));
break; break;
#endif #endif
#ifdef HAVE_FDATASYNC #ifdef HAVE_FDATASYNC
...@@ -9051,8 +8977,8 @@ issue_xlog_fsync(int fd, uint32 log, uint32 seg) ...@@ -9051,8 +8977,8 @@ issue_xlog_fsync(int fd, uint32 log, uint32 seg)
if (pg_fdatasync(fd) != 0) if (pg_fdatasync(fd) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not fdatasync log file %u, segment %u: %m", errmsg("could not fdatasync log file %s: %m",
log, seg))); XLogFileNameP(ThisTimeLineID, openLogSegNo))));
break; break;
#endif #endif
case SYNC_METHOD_OPEN: case SYNC_METHOD_OPEN:
...@@ -9065,6 +8991,17 @@ issue_xlog_fsync(int fd, uint32 log, uint32 seg) ...@@ -9065,6 +8991,17 @@ issue_xlog_fsync(int fd, uint32 log, uint32 seg)
} }
} }
/*
* Return the filename of given log segment, as a palloc'd string.
*/
char *
XLogFileNameP(TimeLineID tli, XLogSegNo segno)
{
char *result = palloc(MAXFNAMELEN);
XLogFileName(result, tli, segno);
return result;
}
/* /*
* do_pg_start_backup is the workhorse of the user-visible pg_start_backup() * do_pg_start_backup is the workhorse of the user-visible pg_start_backup()
* function. It creates the necessary starting checkpoint and constructs the * function. It creates the necessary starting checkpoint and constructs the
...@@ -9096,8 +9033,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile) ...@@ -9096,8 +9033,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
pg_time_t stamp_time; pg_time_t stamp_time;
char strfbuf[128]; char strfbuf[128];
char xlogfilename[MAXFNAMELEN]; char xlogfilename[MAXFNAMELEN];
uint32 _logId; XLogSegNo _logSegNo;
uint32 _logSeg;
struct stat stat_buf; struct stat stat_buf;
FILE *fp; FILE *fp;
StringInfoData labelfbuf; StringInfoData labelfbuf;
...@@ -9293,8 +9229,8 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile) ...@@ -9293,8 +9229,8 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
LWLockRelease(WALInsertLock); LWLockRelease(WALInsertLock);
} while (!gotUniqueStartpoint); } while (!gotUniqueStartpoint);
XLByteToSeg(startpoint, _logId, _logSeg); XLByteToSeg(startpoint, _logSegNo);
XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg); XLogFileName(xlogfilename, ThisTimeLineID, _logSegNo);
/* /*
* Construct backup label file * Construct backup label file
...@@ -9420,8 +9356,7 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive) ...@@ -9420,8 +9356,7 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
char lastxlogfilename[MAXFNAMELEN]; char lastxlogfilename[MAXFNAMELEN];
char histfilename[MAXFNAMELEN]; char histfilename[MAXFNAMELEN];
char backupfrom[20]; char backupfrom[20];
uint32 _logId; XLogSegNo _logSegNo;
uint32 _logSeg;
FILE *lfp; FILE *lfp;
FILE *fp; FILE *fp;
char ch; char ch;
...@@ -9632,8 +9567,8 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive) ...@@ -9632,8 +9567,8 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
*/ */
RequestXLogSwitch(); RequestXLogSwitch();
XLByteToPrevSeg(stoppoint, _logId, _logSeg); XLByteToPrevSeg(stoppoint, _logSegNo);
XLogFileName(stopxlogfilename, ThisTimeLineID, _logId, _logSeg); XLogFileName(stopxlogfilename, ThisTimeLineID, _logSegNo);
/* Use the log timezone here, not the session timezone */ /* Use the log timezone here, not the session timezone */
stamp_time = (pg_time_t) time(NULL); stamp_time = (pg_time_t) time(NULL);
...@@ -9644,8 +9579,8 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive) ...@@ -9644,8 +9579,8 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
/* /*
* Write the backup history file * Write the backup history file
*/ */
XLByteToSeg(startpoint, _logId, _logSeg); XLByteToSeg(startpoint, _logSegNo);
BackupHistoryFilePath(histfilepath, ThisTimeLineID, _logId, _logSeg, BackupHistoryFilePath(histfilepath, ThisTimeLineID, _logSegNo,
startpoint.xrecoff % XLogSegSize); startpoint.xrecoff % XLogSegSize);
fp = AllocateFile(histfilepath, "w"); fp = AllocateFile(histfilepath, "w");
if (!fp) if (!fp)
...@@ -9694,11 +9629,11 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive) ...@@ -9694,11 +9629,11 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
*/ */
if (waitforarchive && XLogArchivingActive()) if (waitforarchive && XLogArchivingActive())
{ {
XLByteToPrevSeg(stoppoint, _logId, _logSeg); XLByteToPrevSeg(stoppoint, _logSegNo);
XLogFileName(lastxlogfilename, ThisTimeLineID, _logId, _logSeg); XLogFileName(lastxlogfilename, ThisTimeLineID, _logSegNo);
XLByteToSeg(startpoint, _logId, _logSeg); XLByteToSeg(startpoint, _logSegNo);
BackupHistoryFileName(histfilename, ThisTimeLineID, _logId, _logSeg, BackupHistoryFileName(histfilename, ThisTimeLineID, _logSegNo,
startpoint.xrecoff % XLogSegSize); startpoint.xrecoff % XLogSegSize);
seconds_before_warning = 60; seconds_before_warning = 60;
...@@ -10036,16 +9971,15 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt, ...@@ -10036,16 +9971,15 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
bool switched_segment = false; bool switched_segment = false;
uint32 targetPageOff; uint32 targetPageOff;
uint32 targetRecOff; uint32 targetRecOff;
uint32 targetId; XLogSegNo targetSegNo;
uint32 targetSeg;
static pg_time_t last_fail_time = 0; static pg_time_t last_fail_time = 0;
XLByteToSeg(*RecPtr, targetId, targetSeg); XLByteToSeg(*RecPtr, targetSegNo);
targetPageOff = ((RecPtr->xrecoff % XLogSegSize) / XLOG_BLCKSZ) * XLOG_BLCKSZ; targetPageOff = ((RecPtr->xrecoff % XLogSegSize) / XLOG_BLCKSZ) * XLOG_BLCKSZ;
targetRecOff = RecPtr->xrecoff % XLOG_BLCKSZ; targetRecOff = RecPtr->xrecoff % XLOG_BLCKSZ;
/* Fast exit if we have read the record in the current buffer already */ /* Fast exit if we have read the record in the current buffer already */
if (failedSources == 0 && targetId == readId && targetSeg == readSeg && if (failedSources == 0 && targetSegNo == readSegNo &&
targetPageOff == readOff && targetRecOff < readLen) targetPageOff == readOff && targetRecOff < readLen)
return true; return true;
...@@ -10053,7 +9987,7 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt, ...@@ -10053,7 +9987,7 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
* See if we need to switch to a new segment because the requested record * See if we need to switch to a new segment because the requested record
* is not in the currently open one. * is not in the currently open one.
*/ */
if (readFile >= 0 && !XLByteInSeg(*RecPtr, readId, readSeg)) if (readFile >= 0 && !XLByteInSeg(*RecPtr, readSegNo))
{ {
/* /*
* Request a restartpoint if we've replayed too much xlog since the * Request a restartpoint if we've replayed too much xlog since the
...@@ -10061,10 +9995,10 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt, ...@@ -10061,10 +9995,10 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
*/ */
if (StandbyMode && bgwriterLaunched) if (StandbyMode && bgwriterLaunched)
{ {
if (XLogCheckpointNeeded(readId, readSeg)) if (XLogCheckpointNeeded(readSegNo))
{ {
(void) GetRedoRecPtr(); (void) GetRedoRecPtr();
if (XLogCheckpointNeeded(readId, readSeg)) if (XLogCheckpointNeeded(readSegNo))
RequestCheckpoint(CHECKPOINT_CAUSE_XLOG); RequestCheckpoint(CHECKPOINT_CAUSE_XLOG);
} }
} }
...@@ -10074,7 +10008,7 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt, ...@@ -10074,7 +10008,7 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
readSource = 0; readSource = 0;
} }
XLByteToSeg(*RecPtr, readId, readSeg); XLByteToSeg(*RecPtr, readSegNo);
retry: retry:
/* See if we need to retrieve more data */ /* See if we need to retrieve more data */
...@@ -10152,7 +10086,7 @@ retry: ...@@ -10152,7 +10086,7 @@ retry:
if (readFile < 0) if (readFile < 0)
{ {
readFile = readFile =
XLogFileRead(readId, readSeg, PANIC, XLogFileRead(readSegNo, PANIC,
recoveryTargetTLI, recoveryTargetTLI,
XLOG_FROM_STREAM, false); XLOG_FROM_STREAM, false);
Assert(readFile >= 0); Assert(readFile >= 0);
...@@ -10258,7 +10192,7 @@ retry: ...@@ -10258,7 +10192,7 @@ retry:
} }
/* Don't try to read from a source that just failed */ /* Don't try to read from a source that just failed */
sources &= ~failedSources; sources &= ~failedSources;
readFile = XLogFileReadAnyTLI(readId, readSeg, DEBUG2, readFile = XLogFileReadAnyTLI(readSegNo, DEBUG2,
sources); sources);
switched_segment = true; switched_segment = true;
if (readFile >= 0) if (readFile >= 0)
...@@ -10301,8 +10235,7 @@ retry: ...@@ -10301,8 +10235,7 @@ retry:
if (InArchiveRecovery) if (InArchiveRecovery)
sources |= XLOG_FROM_ARCHIVE; sources |= XLOG_FROM_ARCHIVE;
readFile = XLogFileReadAnyTLI(readId, readSeg, emode, readFile = XLogFileReadAnyTLI(readSegNo, emode, sources);
sources);
switched_segment = true; switched_segment = true;
if (readFile < 0) if (readFile < 0)
return false; return false;
...@@ -10347,10 +10280,12 @@ retry: ...@@ -10347,10 +10280,12 @@ retry:
readOff = 0; readOff = 0;
if (read(readFile, readBuf, XLOG_BLCKSZ) != XLOG_BLCKSZ) if (read(readFile, readBuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
{ {
char fname[MAXFNAMELEN];
XLogFileName(fname, curFileTLI, readSegNo);
ereport(emode_for_corrupt_record(emode, *RecPtr), ereport(emode_for_corrupt_record(emode, *RecPtr),
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read from log file %u, segment %u, offset %u: %m", errmsg("could not read from log segment %s, offset %u: %m",
readId, readSeg, readOff))); fname, readOff)));
goto next_record_is_invalid; goto next_record_is_invalid;
} }
if (!ValidXLOGHeader((XLogPageHeader) readBuf, emode)) if (!ValidXLOGHeader((XLogPageHeader) readBuf, emode))
...@@ -10361,25 +10296,28 @@ retry: ...@@ -10361,25 +10296,28 @@ retry:
readOff = targetPageOff; readOff = targetPageOff;
if (lseek(readFile, (off_t) readOff, SEEK_SET) < 0) if (lseek(readFile, (off_t) readOff, SEEK_SET) < 0)
{ {
char fname[MAXFNAMELEN];
XLogFileName(fname, curFileTLI, readSegNo);
ereport(emode_for_corrupt_record(emode, *RecPtr), ereport(emode_for_corrupt_record(emode, *RecPtr),
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not seek in log file %u, segment %u to offset %u: %m", errmsg("could not seek in log segment %s to offset %u: %m",
readId, readSeg, readOff))); fname, readOff)));
goto next_record_is_invalid; goto next_record_is_invalid;
} }
if (read(readFile, readBuf, XLOG_BLCKSZ) != XLOG_BLCKSZ) if (read(readFile, readBuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
{ {
char fname[MAXFNAMELEN];
XLogFileName(fname, curFileTLI, readSegNo);
ereport(emode_for_corrupt_record(emode, *RecPtr), ereport(emode_for_corrupt_record(emode, *RecPtr),
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read from log file %u, segment %u, offset %u: %m", errmsg("could not read from log segment %s, offset %u: %m",
readId, readSeg, readOff))); fname, readOff)));
goto next_record_is_invalid; goto next_record_is_invalid;
} }
if (!ValidXLOGHeader((XLogPageHeader) readBuf, emode)) if (!ValidXLOGHeader((XLogPageHeader) readBuf, emode))
goto next_record_is_invalid; goto next_record_is_invalid;
Assert(targetId == readId); Assert(targetSegNo == readSegNo);
Assert(targetSeg == readSeg);
Assert(targetPageOff == readOff); Assert(targetPageOff == readOff);
Assert(targetRecOff < readLen); Assert(targetRecOff < readLen);
......
...@@ -271,8 +271,7 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS) ...@@ -271,8 +271,7 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
char *locationstr; char *locationstr;
unsigned int uxlogid; unsigned int uxlogid;
unsigned int uxrecoff; unsigned int uxrecoff;
uint32 xlogid; XLogSegNo xlogsegno;
uint32 xlogseg;
uint32 xrecoff; uint32 xrecoff;
XLogRecPtr locationpoint; XLogRecPtr locationpoint;
char xlogfilename[MAXFNAMELEN]; char xlogfilename[MAXFNAMELEN];
...@@ -319,8 +318,8 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS) ...@@ -319,8 +318,8 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
/* /*
* xlogfilename * xlogfilename
*/ */
XLByteToPrevSeg(locationpoint, xlogid, xlogseg); XLByteToPrevSeg(locationpoint, xlogsegno);
XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg); XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
values[0] = CStringGetTextDatum(xlogfilename); values[0] = CStringGetTextDatum(xlogfilename);
isnull[0] = false; isnull[0] = false;
...@@ -328,7 +327,7 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS) ...@@ -328,7 +327,7 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
/* /*
* offset * offset
*/ */
xrecoff = locationpoint.xrecoff - xlogseg * XLogSegSize; xrecoff = locationpoint.xrecoff % XLogSegSize;
values[1] = UInt32GetDatum(xrecoff); values[1] = UInt32GetDatum(xrecoff);
isnull[1] = false; isnull[1] = false;
...@@ -354,8 +353,7 @@ pg_xlogfile_name(PG_FUNCTION_ARGS) ...@@ -354,8 +353,7 @@ pg_xlogfile_name(PG_FUNCTION_ARGS)
char *locationstr; char *locationstr;
unsigned int uxlogid; unsigned int uxlogid;
unsigned int uxrecoff; unsigned int uxrecoff;
uint32 xlogid; XLogSegNo xlogsegno;
uint32 xlogseg;
XLogRecPtr locationpoint; XLogRecPtr locationpoint;
char xlogfilename[MAXFNAMELEN]; char xlogfilename[MAXFNAMELEN];
...@@ -378,8 +376,8 @@ pg_xlogfile_name(PG_FUNCTION_ARGS) ...@@ -378,8 +376,8 @@ pg_xlogfile_name(PG_FUNCTION_ARGS)
locationpoint.xlogid = uxlogid; locationpoint.xlogid = uxlogid;
locationpoint.xrecoff = uxrecoff; locationpoint.xrecoff = uxrecoff;
XLByteToPrevSeg(locationpoint, xlogid, xlogseg); XLByteToPrevSeg(locationpoint, xlogsegno);
XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg); XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
PG_RETURN_TEXT_P(cstring_to_text(xlogfilename)); PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
} }
...@@ -514,6 +512,8 @@ pg_xlog_location_diff(PG_FUNCTION_ARGS) ...@@ -514,6 +512,8 @@ pg_xlog_location_diff(PG_FUNCTION_ARGS)
XLogRecPtr loc1, XLogRecPtr loc1,
loc2; loc2;
Numeric result; Numeric result;
uint64 bytes1,
bytes2;
/* /*
* Read and parse input * Read and parse input
...@@ -533,33 +533,17 @@ pg_xlog_location_diff(PG_FUNCTION_ARGS) ...@@ -533,33 +533,17 @@ pg_xlog_location_diff(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not parse transaction log location \"%s\"", str2))); errmsg("could not parse transaction log location \"%s\"", str2)));
/* bytes1 = (((uint64)loc1.xlogid) << 32L) + loc1.xrecoff;
* Sanity check bytes2 = (((uint64)loc2.xlogid) << 32L) + loc2.xrecoff;
*/
if (loc1.xrecoff > XLogFileSize)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("xrecoff \"%X\" is out of valid range, 0..%X", loc1.xrecoff, XLogFileSize)));
if (loc2.xrecoff > XLogFileSize)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("xrecoff \"%X\" is out of valid range, 0..%X", loc2.xrecoff, XLogFileSize)));
/* /*
* result = XLogFileSize * (xlogid1 - xlogid2) + xrecoff1 - xrecoff2 * result = bytes1 - bytes2.
*
* XXX: this won't handle values higher than 2^63 correctly.
*/ */
result = DatumGetNumeric(DirectFunctionCall2(numeric_sub, result = DatumGetNumeric(DirectFunctionCall2(numeric_sub,
DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc1.xlogid)), DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) bytes1)),
DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc2.xlogid)))); DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) bytes2))));
result = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) XLogFileSize)),
NumericGetDatum(result)));
result = DatumGetNumeric(DirectFunctionCall2(numeric_add,
NumericGetDatum(result),
DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc1.xrecoff))));
result = DatumGetNumeric(DirectFunctionCall2(numeric_sub,
NumericGetDatum(result),
DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc2.xrecoff))));
PG_RETURN_NUMERIC(result); PG_RETURN_NUMERIC(result);
} }
......
...@@ -779,7 +779,7 @@ IsCheckpointOnSchedule(double progress) ...@@ -779,7 +779,7 @@ IsCheckpointOnSchedule(double progress)
{ {
recptr = GetInsertRecPtr(); recptr = GetInsertRecPtr();
elapsed_xlogs = elapsed_xlogs =
(((double) (int32) (recptr.xlogid - ckpt_start_recptr.xlogid)) * XLogSegsPerFile + (((double) ((uint64) (recptr.xlogid - ckpt_start_recptr.xlogid) << 32L)) +
((double) recptr.xrecoff - (double) ckpt_start_recptr.xrecoff) / XLogSegSize) / ((double) recptr.xrecoff - (double) ckpt_start_recptr.xrecoff) / XLogSegSize) /
CheckPointSegments; CheckPointSegments;
......
...@@ -221,10 +221,8 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -221,10 +221,8 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
* We've left the last tar file "open", so we can now append the * We've left the last tar file "open", so we can now append the
* required WAL files to it. * required WAL files to it.
*/ */
uint32 logid, XLogSegNo logsegno;
logseg; XLogSegNo endlogsegno;
uint32 endlogid,
endlogseg;
struct stat statbuf; struct stat statbuf;
MemSet(&statbuf, 0, sizeof(statbuf)); MemSet(&statbuf, 0, sizeof(statbuf));
...@@ -236,8 +234,8 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -236,8 +234,8 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
statbuf.st_size = XLogSegSize; statbuf.st_size = XLogSegSize;
statbuf.st_mtime = time(NULL); statbuf.st_mtime = time(NULL);
XLByteToSeg(startptr, logid, logseg); XLByteToSeg(startptr, logsegno);
XLByteToPrevSeg(endptr, endlogid, endlogseg); XLByteToPrevSeg(endptr, endlogsegno);
while (true) while (true)
{ {
...@@ -245,7 +243,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -245,7 +243,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
char fn[MAXPGPATH]; char fn[MAXPGPATH];
int i; int i;
XLogFilePath(fn, ThisTimeLineID, logid, logseg); XLogFilePath(fn, ThisTimeLineID, logsegno);
_tarWriteHeader(fn, NULL, &statbuf); _tarWriteHeader(fn, NULL, &statbuf);
/* Send the actual WAL file contents, block-by-block */ /* Send the actual WAL file contents, block-by-block */
...@@ -254,8 +252,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -254,8 +252,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
char buf[TAR_SEND_SIZE]; char buf[TAR_SEND_SIZE];
XLogRecPtr ptr; XLogRecPtr ptr;
ptr.xlogid = logid; XLogSegNoOffsetToRecPtr(logsegno, TAR_SEND_SIZE * i, ptr);
ptr.xrecoff = logseg * XLogSegSize + TAR_SEND_SIZE * i;
/* /*
* Some old compilers, e.g. gcc 2.95.3/x86, think that passing * Some old compilers, e.g. gcc 2.95.3/x86, think that passing
...@@ -277,11 +274,10 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -277,11 +274,10 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
/* Advance to the next WAL file */ /* Advance to the next WAL file */
NextLogSeg(logid, logseg); logsegno++;
/* Have we reached our stop position yet? */ /* Have we reached our stop position yet? */
if (logid > endlogid || if (logsegno > endlogsegno)
(logid == endlogid && logseg > endlogseg))
break; break;
} }
......
...@@ -69,11 +69,12 @@ walrcv_disconnect_type walrcv_disconnect = NULL; ...@@ -69,11 +69,12 @@ walrcv_disconnect_type walrcv_disconnect = NULL;
/* /*
* These variables are used similarly to openLogFile/Id/Seg/Off, * These variables are used similarly to openLogFile/Id/Seg/Off,
* but for walreceiver to write the XLOG. * but for walreceiver to write the XLOG. recvFileTLI is the TimeLineID
* corresponding the filename of recvFile, used for error messages.
*/ */
static int recvFile = -1; static int recvFile = -1;
static uint32 recvId = 0; static TimeLineID recvFileTLI = -1;
static uint32 recvSeg = 0; static XLogSegNo recvSegNo = 0;
static uint32 recvOff = 0; static uint32 recvOff = 0;
/* /*
...@@ -481,7 +482,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) ...@@ -481,7 +482,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
{ {
int segbytes; int segbytes;
if (recvFile < 0 || !XLByteInSeg(recptr, recvId, recvSeg)) if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo))
{ {
bool use_existent; bool use_existent;
...@@ -501,15 +502,16 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) ...@@ -501,15 +502,16 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
if (close(recvFile) != 0) if (close(recvFile) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not close log file %u, segment %u: %m", errmsg("could not close log segment %s: %m",
recvId, recvSeg))); XLogFileNameP(recvFileTLI, recvSegNo))));
} }
recvFile = -1; recvFile = -1;
/* Create/use new log file */ /* Create/use new log file */
XLByteToSeg(recptr, recvId, recvSeg); XLByteToSeg(recptr, recvSegNo);
use_existent = true; use_existent = true;
recvFile = XLogFileInit(recvId, recvSeg, &use_existent, true); recvFile = XLogFileInit(recvSegNo, &use_existent, true);
recvFileTLI = ThisTimeLineID;
recvOff = 0; recvOff = 0;
} }
...@@ -527,9 +529,9 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) ...@@ -527,9 +529,9 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
if (lseek(recvFile, (off_t) startoff, SEEK_SET) < 0) if (lseek(recvFile, (off_t) startoff, SEEK_SET) < 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not seek in log file %u, " errmsg("could not seek in log segment %s, to offset %u: %m",
"segment %u to offset %u: %m", XLogFileNameP(recvFileTLI, recvSegNo),
recvId, recvSeg, startoff))); startoff)));
recvOff = startoff; recvOff = startoff;
} }
...@@ -544,9 +546,9 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) ...@@ -544,9 +546,9 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
errno = ENOSPC; errno = ENOSPC;
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write to log file %u, segment %u " errmsg("could not write to log segment %s "
"at offset %u, length %lu: %m", "at offset %u, length %lu: %m",
recvId, recvSeg, XLogFileNameP(recvFileTLI, recvSegNo),
recvOff, (unsigned long) segbytes))); recvOff, (unsigned long) segbytes)));
} }
...@@ -575,7 +577,7 @@ XLogWalRcvFlush(bool dying) ...@@ -575,7 +577,7 @@ XLogWalRcvFlush(bool dying)
/* use volatile pointer to prevent code rearrangement */ /* use volatile pointer to prevent code rearrangement */
volatile WalRcvData *walrcv = WalRcv; volatile WalRcvData *walrcv = WalRcv;
issue_xlog_fsync(recvFile, recvId, recvSeg); issue_xlog_fsync(recvFile, recvSegNo);
LogstreamResult.Flush = LogstreamResult.Write; LogstreamResult.Flush = LogstreamResult.Write;
......
...@@ -87,8 +87,7 @@ int replication_timeout = 60 * 1000; /* maximum time to send one ...@@ -87,8 +87,7 @@ int replication_timeout = 60 * 1000; /* maximum time to send one
* but for walsender to read the XLOG. * but for walsender to read the XLOG.
*/ */
static int sendFile = -1; static int sendFile = -1;
static uint32 sendId = 0; static XLogSegNo sendSegNo = 0;
static uint32 sendSeg = 0;
static uint32 sendOff = 0; static uint32 sendOff = 0;
/* /*
...@@ -977,10 +976,8 @@ XLogRead(char *buf, XLogRecPtr startptr, Size count) ...@@ -977,10 +976,8 @@ XLogRead(char *buf, XLogRecPtr startptr, Size count)
char *p; char *p;
XLogRecPtr recptr; XLogRecPtr recptr;
Size nbytes; Size nbytes;
uint32 lastRemovedLog; XLogSegNo lastRemovedSegNo;
uint32 lastRemovedSeg; XLogSegNo segno;
uint32 log;
uint32 seg;
retry: retry:
p = buf; p = buf;
...@@ -995,7 +992,7 @@ retry: ...@@ -995,7 +992,7 @@ retry:
startoff = recptr.xrecoff % XLogSegSize; startoff = recptr.xrecoff % XLogSegSize;
if (sendFile < 0 || !XLByteInSeg(recptr, sendId, sendSeg)) if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo))
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
...@@ -1003,8 +1000,8 @@ retry: ...@@ -1003,8 +1000,8 @@ retry:
if (sendFile >= 0) if (sendFile >= 0)
close(sendFile); close(sendFile);
XLByteToSeg(recptr, sendId, sendSeg); XLByteToSeg(recptr, sendSegNo);
XLogFilePath(path, ThisTimeLineID, sendId, sendSeg); XLogFilePath(path, ThisTimeLineID, sendSegNo);
sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0); sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
if (sendFile < 0) if (sendFile < 0)
...@@ -1015,20 +1012,15 @@ retry: ...@@ -1015,20 +1012,15 @@ retry:
* removed or recycled. * removed or recycled.
*/ */
if (errno == ENOENT) if (errno == ENOENT)
{
char filename[MAXFNAMELEN];
XLogFileName(filename, ThisTimeLineID, sendId, sendSeg);
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("requested WAL segment %s has already been removed", errmsg("requested WAL segment %s has already been removed",
filename))); XLogFileNameP(ThisTimeLineID, sendSegNo))));
}
else else
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file \"%s\" (log file %u, segment %u): %m", errmsg("could not open file \"%s\": %m",
path, sendId, sendSeg))); path)));
} }
sendOff = 0; sendOff = 0;
} }
...@@ -1039,8 +1031,9 @@ retry: ...@@ -1039,8 +1031,9 @@ retry:
if (lseek(sendFile, (off_t) startoff, SEEK_SET) < 0) if (lseek(sendFile, (off_t) startoff, SEEK_SET) < 0)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not seek in log file %u, segment %u to offset %u: %m", errmsg("could not seek in log segment %s to offset %u: %m",
sendId, sendSeg, startoff))); XLogFileNameP(ThisTimeLineID, sendSegNo),
startoff)));
sendOff = startoff; sendOff = startoff;
} }
...@@ -1052,11 +1045,13 @@ retry: ...@@ -1052,11 +1045,13 @@ retry:
readbytes = read(sendFile, p, segbytes); readbytes = read(sendFile, p, segbytes);
if (readbytes <= 0) if (readbytes <= 0)
{
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read from log file %u, segment %u, offset %u, " errmsg("could not read from log segment %s, offset %u, length %lu: %m",
"length %lu: %m", XLogFileNameP(ThisTimeLineID, sendSegNo),
sendId, sendSeg, sendOff, (unsigned long) segbytes))); sendOff, (unsigned long) segbytes)));
}
/* Update state for read */ /* Update state for read */
XLByteAdvance(recptr, readbytes); XLByteAdvance(recptr, readbytes);
...@@ -1073,19 +1068,13 @@ retry: ...@@ -1073,19 +1068,13 @@ retry:
* read() succeeds in that case, but the data we tried to read might * read() succeeds in that case, but the data we tried to read might
* already have been overwritten with new WAL records. * already have been overwritten with new WAL records.
*/ */
XLogGetLastRemoved(&lastRemovedLog, &lastRemovedSeg); XLogGetLastRemoved(&lastRemovedSegNo);
XLByteToSeg(startptr, log, seg); XLByteToSeg(startptr, segno);
if (log < lastRemovedLog || if (segno <= lastRemovedSegNo)
(log == lastRemovedLog && seg <= lastRemovedSeg))
{
char filename[MAXFNAMELEN];
XLogFileName(filename, ThisTimeLineID, log, seg);
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("requested WAL segment %s has already been removed", errmsg("requested WAL segment %s has already been removed",
filename))); XLogFileNameP(ThisTimeLineID, segno))));
}
/* /*
* During recovery, the currently-open WAL file might be replaced with the * During recovery, the currently-open WAL file might be replaced with the
...@@ -1165,24 +1154,13 @@ XLogSend(char *msgbuf, bool *caughtup) ...@@ -1165,24 +1154,13 @@ XLogSend(char *msgbuf, bool *caughtup)
* SendRqstPtr never points to the middle of a WAL record. * SendRqstPtr never points to the middle of a WAL record.
*/ */
startptr = sentPtr; startptr = sentPtr;
if (startptr.xrecoff >= XLogFileSize)
{
/*
* crossing a logid boundary, skip the non-existent last log segment
* in previous logical log file.
*/
startptr.xlogid += 1;
startptr.xrecoff = 0;
}
endptr = startptr; endptr = startptr;
XLByteAdvance(endptr, MAX_SEND_SIZE); XLByteAdvance(endptr, MAX_SEND_SIZE);
if (endptr.xlogid != startptr.xlogid) if (endptr.xlogid != startptr.xlogid)
{ {
/* Don't cross a logfile boundary within one message */ /* Don't cross a logfile boundary within one message */
Assert(endptr.xlogid == startptr.xlogid + 1); Assert(endptr.xlogid == startptr.xlogid + 1);
endptr.xlogid = startptr.xlogid; endptr.xrecoff = 0;
endptr.xrecoff = XLogFileSize;
} }
/* if we went beyond SendRqstPtr, back off */ /* if we went beyond SendRqstPtr, back off */
...@@ -1198,7 +1176,10 @@ XLogSend(char *msgbuf, bool *caughtup) ...@@ -1198,7 +1176,10 @@ XLogSend(char *msgbuf, bool *caughtup)
*caughtup = false; *caughtup = false;
} }
nbytes = endptr.xrecoff - startptr.xrecoff; if (endptr.xrecoff == 0)
nbytes = 0x100000000L - (uint64) startptr.xrecoff;
else
nbytes = endptr.xrecoff - startptr.xrecoff;
Assert(nbytes <= MAX_SEND_SIZE); Assert(nbytes <= MAX_SEND_SIZE);
/* /*
......
...@@ -102,8 +102,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) ...@@ -102,8 +102,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline)
struct dirent *dirent; struct dirent *dirent;
int i; int i;
bool b; bool b;
uint32 high_log = 0; XLogSegNo high_segno = 0;
uint32 high_seg = 0;
dir = opendir(basedir); dir = opendir(basedir);
if (dir == NULL) if (dir == NULL)
...@@ -117,9 +116,10 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) ...@@ -117,9 +116,10 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline)
{ {
char fullpath[MAXPGPATH]; char fullpath[MAXPGPATH];
struct stat statbuf; struct stat statbuf;
uint32 tli, uint32 tli;
log, unsigned int log,
seg; seg;
XLogSegNo segno;
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
continue; continue;
...@@ -151,6 +151,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) ...@@ -151,6 +151,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline)
progname, dirent->d_name); progname, dirent->d_name);
disconnect_and_exit(1); disconnect_and_exit(1);
} }
segno = ((uint64) log) << 32 | seg;
/* Ignore any files that are for another timeline */ /* Ignore any files that are for another timeline */
if (tli != currenttimeline) if (tli != currenttimeline)
...@@ -168,11 +169,9 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) ...@@ -168,11 +169,9 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline)
if (statbuf.st_size == XLOG_SEG_SIZE) if (statbuf.st_size == XLOG_SEG_SIZE)
{ {
/* Completed segment */ /* Completed segment */
if (log > high_log || if (segno > high_segno)
(log == high_log && seg > high_seg))
{ {
high_log = log; high_segno = segno;
high_seg = seg;
continue; continue;
} }
} }
...@@ -186,7 +185,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) ...@@ -186,7 +185,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline)
closedir(dir); closedir(dir);
if (high_log > 0 || high_seg > 0) if (high_segno > 0)
{ {
XLogRecPtr high_ptr; XLogRecPtr high_ptr;
...@@ -194,10 +193,9 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) ...@@ -194,10 +193,9 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline)
* Move the starting pointer to the start of the next segment, since * Move the starting pointer to the start of the next segment, since
* the highest one we've seen was completed. * the highest one we've seen was completed.
*/ */
NextLogSeg(high_log, high_seg); high_segno++;
high_ptr.xlogid = high_log; XLogSegNoOffsetToRecPtr(high_segno, 0, high_ptr);
high_ptr.xrecoff = high_seg * XLOG_SEG_SIZE;
return high_ptr; return high_ptr;
} }
......
...@@ -55,9 +55,10 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu ...@@ -55,9 +55,10 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu
struct stat statbuf; struct stat statbuf;
char *zerobuf; char *zerobuf;
int bytes; int bytes;
XLogSegNo segno;
XLogFileName(namebuf, timeline, startpoint.xlogid, XLByteToSeg(startpoint, segno);
startpoint.xrecoff / XLOG_SEG_SIZE); XLogFileName(namebuf, timeline, segno);
snprintf(fn, sizeof(fn), "%s/%s.partial", basedir, namebuf); snprintf(fn, sizeof(fn), "%s/%s.partial", basedir, namebuf);
f = open(fn, O_WRONLY | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR); f = open(fn, O_WRONLY | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR);
......
...@@ -60,8 +60,7 @@ extern char *optarg; ...@@ -60,8 +60,7 @@ extern char *optarg;
static ControlFileData ControlFile; /* pg_control values */ static ControlFileData ControlFile; /* pg_control values */
static uint32 newXlogId, static XLogSegNo newXlogSegNo; /* new XLOG segment # */
newXlogSeg; /* ID/Segment of new XLOG segment */
static bool guessed = false; /* T if we had to guess at any values */ static bool guessed = false; /* T if we had to guess at any values */
static const char *progname; static const char *progname;
...@@ -87,12 +86,9 @@ main(int argc, char *argv[]) ...@@ -87,12 +86,9 @@ main(int argc, char *argv[])
Oid set_oid = 0; Oid set_oid = 0;
MultiXactId set_mxid = 0; MultiXactId set_mxid = 0;
MultiXactOffset set_mxoff = (MultiXactOffset) -1; MultiXactOffset set_mxoff = (MultiXactOffset) -1;
uint32 minXlogTli = 0, uint32 minXlogTli = 0;
minXlogId = 0, XLogSegNo minXlogSegNo = 0;
minXlogSeg = 0;
char *endptr; char *endptr;
char *endptr2;
char *endptr3;
char *DataDir; char *DataDir;
int fd; int fd;
char path[MAXPGPATH]; char path[MAXPGPATH];
...@@ -204,27 +200,13 @@ main(int argc, char *argv[]) ...@@ -204,27 +200,13 @@ main(int argc, char *argv[])
break; break;
case 'l': case 'l':
minXlogTli = strtoul(optarg, &endptr, 0); if (strspn(optarg, "01234567890ABCDEFabcdef") != 24)
if (endptr == optarg || *endptr != ',')
{
fprintf(stderr, _("%s: invalid argument for option -l\n"), progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
}
minXlogId = strtoul(endptr + 1, &endptr2, 0);
if (endptr2 == endptr + 1 || *endptr2 != ',')
{
fprintf(stderr, _("%s: invalid argument for option -l\n"), progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
}
minXlogSeg = strtoul(endptr2 + 1, &endptr3, 0);
if (endptr3 == endptr2 + 1 || *endptr3 != '\0')
{ {
fprintf(stderr, _("%s: invalid argument for option -l\n"), progname); fprintf(stderr, _("%s: invalid argument for option -l\n"), progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1); exit(1);
} }
XLogFromFileName(optarg, &minXlogTli, &minXlogSegNo);
break; break;
default: default:
...@@ -295,7 +277,7 @@ main(int argc, char *argv[]) ...@@ -295,7 +277,7 @@ main(int argc, char *argv[])
GuessControlValues(); GuessControlValues();
/* /*
* Also look at existing segment files to set up newXlogId/newXlogSeg * Also look at existing segment files to set up newXlogSegNo
*/ */
FindEndOfXLOG(); FindEndOfXLOG();
...@@ -335,13 +317,8 @@ main(int argc, char *argv[]) ...@@ -335,13 +317,8 @@ main(int argc, char *argv[])
if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID) if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli; ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
if (minXlogId > newXlogId || if (minXlogSegNo > newXlogSegNo)
(minXlogId == newXlogId && newXlogSegNo = minXlogSegNo;
minXlogSeg > newXlogSeg))
{
newXlogId = minXlogId;
newXlogSeg = minXlogSeg;
}
/* /*
* If we had to guess anything, and -f was not given, just print the * If we had to guess anything, and -f was not given, just print the
...@@ -545,6 +522,7 @@ static void ...@@ -545,6 +522,7 @@ static void
PrintControlValues(bool guessed) PrintControlValues(bool guessed)
{ {
char sysident_str[32]; char sysident_str[32];
char fname[MAXFNAMELEN];
if (guessed) if (guessed)
printf(_("Guessed pg_control values:\n\n")); printf(_("Guessed pg_control values:\n\n"));
...@@ -558,10 +536,10 @@ PrintControlValues(bool guessed) ...@@ -558,10 +536,10 @@ PrintControlValues(bool guessed)
snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT, snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
ControlFile.system_identifier); ControlFile.system_identifier);
printf(_("First log file ID after reset: %u\n"), XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo);
newXlogId);
printf(_("First log file segment after reset: %u\n"), printf(_("First log segment after reset: %s\n"),
newXlogSeg); fname);
printf(_("pg_control version number: %u\n"), printf(_("pg_control version number: %u\n"),
ControlFile.pg_control_version); ControlFile.pg_control_version);
printf(_("Catalog version number: %u\n"), printf(_("Catalog version number: %u\n"),
...@@ -624,11 +602,10 @@ RewriteControlFile(void) ...@@ -624,11 +602,10 @@ RewriteControlFile(void)
/* /*
* Adjust fields as needed to force an empty XLOG starting at * Adjust fields as needed to force an empty XLOG starting at
* newXlogId/newXlogSeg. * newXlogSegNo.
*/ */
ControlFile.checkPointCopy.redo.xlogid = newXlogId; XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD,
ControlFile.checkPointCopy.redo.xrecoff = ControlFile.checkPointCopy.redo);
newXlogSeg * XLogSegSize + SizeOfXLogLongPHD;
ControlFile.checkPointCopy.time = (pg_time_t) time(NULL); ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
ControlFile.state = DB_SHUTDOWNED; ControlFile.state = DB_SHUTDOWNED;
...@@ -728,14 +705,17 @@ FindEndOfXLOG(void) ...@@ -728,14 +705,17 @@ FindEndOfXLOG(void)
{ {
DIR *xldir; DIR *xldir;
struct dirent *xlde; struct dirent *xlde;
uint64 segs_per_xlogid;
uint64 xlogbytepos;
/* /*
* Initialize the max() computation using the last checkpoint address from * Initialize the max() computation using the last checkpoint address from
* old pg_control. Note that for the moment we are working with segment * old pg_control. Note that for the moment we are working with segment
* numbering according to the old xlog seg size. * numbering according to the old xlog seg size.
*/ */
newXlogId = ControlFile.checkPointCopy.redo.xlogid; segs_per_xlogid = (0x100000000L / ControlFile.xlog_seg_size);
newXlogSeg = ControlFile.checkPointCopy.redo.xrecoff / ControlFile.xlog_seg_size; newXlogSegNo = ((uint64) ControlFile.checkPointCopy.redo.xlogid) * segs_per_xlogid
+ (ControlFile.checkPointCopy.redo.xrecoff / ControlFile.xlog_seg_size);
/* /*
* Scan the pg_xlog directory to find existing WAL segment files. We * Scan the pg_xlog directory to find existing WAL segment files. We
...@@ -759,8 +739,10 @@ FindEndOfXLOG(void) ...@@ -759,8 +739,10 @@ FindEndOfXLOG(void)
unsigned int tli, unsigned int tli,
log, log,
seg; seg;
XLogSegNo segno;
sscanf(xlde->d_name, "%08X%08X%08X", &tli, &log, &seg); sscanf(xlde->d_name, "%08X%08X%08X", &tli, &log, &seg);
segno = ((uint64) log) * segs_per_xlogid + seg;
/* /*
* Note: we take the max of all files found, regardless of their * Note: we take the max of all files found, regardless of their
...@@ -768,12 +750,8 @@ FindEndOfXLOG(void) ...@@ -768,12 +750,8 @@ FindEndOfXLOG(void)
* timelines other than the target TLI, but this seems safer. * timelines other than the target TLI, but this seems safer.
* Better too large a result than too small... * Better too large a result than too small...
*/ */
if (log > newXlogId || if (segno > newXlogSegNo)
(log == newXlogId && seg > newXlogSeg)) newXlogSegNo = segno;
{
newXlogId = log;
newXlogSeg = seg;
}
} }
errno = 0; errno = 0;
} }
...@@ -799,11 +777,9 @@ FindEndOfXLOG(void) ...@@ -799,11 +777,9 @@ FindEndOfXLOG(void)
* Finally, convert to new xlog seg size, and advance by one to ensure we * Finally, convert to new xlog seg size, and advance by one to ensure we
* are in virgin territory. * are in virgin territory.
*/ */
newXlogSeg *= ControlFile.xlog_seg_size; xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
newXlogSeg = (newXlogSeg + XLogSegSize - 1) / XLogSegSize; newXlogSegNo = (xlogbytepos + XLogSegSize - 1) / XLogSegSize;
newXlogSegNo++;
/* be sure we wrap around correctly at end of a logfile */
NextLogSeg(newXlogId, newXlogSeg);
} }
...@@ -972,8 +948,7 @@ WriteEmptyXLOG(void) ...@@ -972,8 +948,7 @@ WriteEmptyXLOG(void)
record->xl_crc = crc; record->xl_crc = crc;
/* Write the first page */ /* Write the first page */
XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID, XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo);
newXlogId, newXlogSeg);
unlink(path); unlink(path);
......
...@@ -267,12 +267,10 @@ extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata); ...@@ -267,12 +267,10 @@ extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
extern void XLogFlush(XLogRecPtr RecPtr); extern void XLogFlush(XLogRecPtr RecPtr);
extern bool XLogBackgroundFlush(void); extern bool XLogBackgroundFlush(void);
extern bool XLogNeedsFlush(XLogRecPtr RecPtr); extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
extern int XLogFileInit(uint32 log, uint32 seg, extern int XLogFileInit(XLogSegNo segno, bool *use_existent, bool use_lock);
bool *use_existent, bool use_lock); extern int XLogFileOpen(XLogSegNo segno);
extern int XLogFileOpen(uint32 log, uint32 seg);
extern void XLogGetLastRemoved(XLogSegNo *segno);
extern void XLogGetLastRemoved(uint32 *log, uint32 *seg);
extern void XLogSetAsyncXactLSN(XLogRecPtr record); extern void XLogSetAsyncXactLSN(XLogRecPtr record);
extern void RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup); extern void RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup);
...@@ -280,7 +278,7 @@ extern void RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup); ...@@ -280,7 +278,7 @@ extern void RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup);
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record); extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, uint8 xl_info, char *rec); extern void xlog_desc(StringInfo buf, uint8 xl_info, char *rec);
extern void issue_xlog_fsync(int fd, uint32 log, uint32 seg); extern void issue_xlog_fsync(int fd, XLogSegNo segno);
extern bool RecoveryInProgress(void); extern bool RecoveryInProgress(void);
extern bool HotStandbyActive(void); extern bool HotStandbyActive(void);
...@@ -294,6 +292,7 @@ extern bool RecoveryIsPaused(void); ...@@ -294,6 +292,7 @@ extern bool RecoveryIsPaused(void);
extern void SetRecoveryPause(bool recoveryPause); extern void SetRecoveryPause(bool recoveryPause);
extern TimestampTz GetLatestXTime(void); extern TimestampTz GetLatestXTime(void);
extern TimestampTz GetCurrentChunkReplayStartTime(void); extern TimestampTz GetCurrentChunkReplayStartTime(void);
extern char *XLogFileNameP(TimeLineID tli, XLogSegNo segno);
extern void UpdateControlFile(void); extern void UpdateControlFile(void);
extern uint64 GetSystemIdentifier(void); extern uint64 GetSystemIdentifier(void);
......
...@@ -71,7 +71,7 @@ typedef struct XLogContRecord ...@@ -71,7 +71,7 @@ typedef struct XLogContRecord
/* /*
* Each page of XLOG file has a header like this: * Each page of XLOG file has a header like this:
*/ */
#define XLOG_PAGE_MAGIC 0xD071 /* can be used as WAL version indicator */ #define XLOG_PAGE_MAGIC 0xD072 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData typedef struct XLogPageHeaderData
{ {
...@@ -115,55 +115,27 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -115,55 +115,27 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
(((hdr)->xlp_info & XLP_LONG_HEADER) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD) (((hdr)->xlp_info & XLP_LONG_HEADER) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD)
/* /*
* We break each logical log file (xlogid value) into segment files of the * The XLOG is split into WAL segments (physical files) of the size indicated
* size indicated by XLOG_SEG_SIZE. One possible segment at the end of each * by XLOG_SEG_SIZE.
* log file is wasted, to ensure that we don't have problems representing
* last-byte-position-plus-1.
*/ */
#define XLogSegSize ((uint32) XLOG_SEG_SIZE) #define XLogSegSize ((uint32) XLOG_SEG_SIZE)
#define XLogSegsPerFile (((uint32) 0xffffffff) / XLogSegSize) #define XLogSegmentsPerXLogId (0x100000000L / XLOG_SEG_SIZE)
#define XLogFileSize (XLogSegsPerFile * XLogSegSize)
#define XLogSegNoOffsetToRecPtr(segno, offset, dest) \
do { \
(dest).xlogid = (segno) / XLogSegmentsPerXLogId; \
(dest).xrecoff = ((segno) % XLogSegmentsPerXLogId) * XLOG_SEG_SIZE + (offset); \
} while (0)
/* /*
* Macros for manipulating XLOG pointers * Macros for manipulating XLOG pointers
*/ */
/* Increment an xlogid/segment pair */
#define NextLogSeg(logId, logSeg) \
do { \
if ((logSeg) >= XLogSegsPerFile-1) \
{ \
(logId)++; \
(logSeg) = 0; \
} \
else \
(logSeg)++; \
} while (0)
/* Decrement an xlogid/segment pair (assume it's not 0,0) */
#define PrevLogSeg(logId, logSeg) \
do { \
if (logSeg) \
(logSeg)--; \
else \
{ \
(logId)--; \
(logSeg) = XLogSegsPerFile-1; \
} \
} while (0)
/* Align a record pointer to next page */ /* Align a record pointer to next page */
#define NextLogPage(recptr) \ #define NextLogPage(recptr) \
do { \ do { \
if ((recptr).xrecoff % XLOG_BLCKSZ != 0) \ if ((recptr).xrecoff % XLOG_BLCKSZ != 0) \
(recptr).xrecoff += \ XLByteAdvance(recptr, (XLOG_BLCKSZ - (recptr).xrecoff % XLOG_BLCKSZ)); \
(XLOG_BLCKSZ - (recptr).xrecoff % XLOG_BLCKSZ); \
if ((recptr).xrecoff >= XLogFileSize) \
{ \
((recptr).xlogid)++; \
(recptr).xrecoff = 0; \
} \
} while (0) } while (0)
/* /*
...@@ -175,14 +147,11 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -175,14 +147,11 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
* for example. (We can assume xrecoff is not zero, since no valid recptr * for example. (We can assume xrecoff is not zero, since no valid recptr
* can have that.) * can have that.)
*/ */
#define XLByteToSeg(xlrp, logId, logSeg) \ #define XLByteToSeg(xlrp, logSegNo) \
( logId = (xlrp).xlogid, \ logSegNo = ((uint64) (xlrp).xlogid * XLogSegmentsPerXLogId) + (xlrp).xrecoff / XLogSegSize
logSeg = (xlrp).xrecoff / XLogSegSize \
) #define XLByteToPrevSeg(xlrp, logSegNo) \
#define XLByteToPrevSeg(xlrp, logId, logSeg) \ logSegNo = ((uint64) (xlrp).xlogid * XLogSegmentsPerXLogId) + ((xlrp).xrecoff - 1) / XLogSegSize
( logId = (xlrp).xlogid, \
logSeg = ((xlrp).xrecoff - 1) / XLogSegSize \
)
/* /*
* Is an XLogRecPtr within a particular XLOG segment? * Is an XLogRecPtr within a particular XLOG segment?
...@@ -190,13 +159,16 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -190,13 +159,16 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
* For XLByteInSeg, do the computation at face value. For XLByteInPrevSeg, * For XLByteInSeg, do the computation at face value. For XLByteInPrevSeg,
* a boundary byte is taken to be in the previous segment. * a boundary byte is taken to be in the previous segment.
*/ */
#define XLByteInSeg(xlrp, logId, logSeg) \ #define XLByteInSeg(xlrp, logSegNo) \
((xlrp).xlogid == (logId) && \ (((xlrp).xlogid) == (logSegNo) / XLogSegmentsPerXLogId && \
(xlrp).xrecoff / XLogSegSize == (logSeg)) ((xlrp).xrecoff / XLogSegSize) == (logSegNo) % XLogSegmentsPerXLogId)
#define XLByteInPrevSeg(xlrp, logId, logSeg) \ #define XLByteInPrevSeg(xlrp, logSegNo) \
((xlrp).xlogid == (logId) && \ (((xlrp).xrecoff == 0) ? \
((xlrp).xrecoff - 1) / XLogSegSize == (logSeg)) (((xlrp).xlogid - 1) == (logSegNo) / XLogSegmentsPerXLogId && \
((uint32) 0xffffffff) / XLogSegSize == (logSegNo) % XLogSegmentsPerXLogId) : \
((xlrp).xlogid) == (logSegNo) / XLogSegmentsPerXLogId && \
(((xlrp).xrecoff - 1) / XLogSegSize) == (logSegNo) % XLogSegmentsPerXLogId)
/* Check if an xrecoff value is in a plausible range */ /* Check if an xrecoff value is in a plausible range */
#define XRecOffIsValid(xrecoff) \ #define XRecOffIsValid(xrecoff) \
...@@ -215,14 +187,23 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -215,14 +187,23 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
*/ */
#define MAXFNAMELEN 64 #define MAXFNAMELEN 64
#define XLogFileName(fname, tli, log, seg) \ #define XLogFileName(fname, tli, logSegNo) \
snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg) snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, \
(uint32) ((logSegNo) / XLogSegmentsPerXLogId), \
#define XLogFromFileName(fname, tli, log, seg) \ (uint32) ((logSegNo) % XLogSegmentsPerXLogId))
sscanf(fname, "%08X%08X%08X", tli, log, seg)
#define XLogFromFileName(fname, tli, logSegNo) \
do { \
uint32 log; \
uint32 seg; \
sscanf(fname, "%08X%08X%08X", tli, &log, &seg); \
*logSegNo = (uint64) log * XLogSegmentsPerXLogId + seg; \
} while (0)
#define XLogFilePath(path, tli, log, seg) \ #define XLogFilePath(path, tli, logSegNo) \
snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, log, seg) snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, \
(uint32) ((logSegNo) / XLogSegmentsPerXLogId), \
(uint32) ((logSegNo) % XLogSegmentsPerXLogId))
#define TLHistoryFileName(fname, tli) \ #define TLHistoryFileName(fname, tli) \
snprintf(fname, MAXFNAMELEN, "%08X.history", tli) snprintf(fname, MAXFNAMELEN, "%08X.history", tli)
...@@ -233,11 +214,15 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -233,11 +214,15 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
#define StatusFilePath(path, xlog, suffix) \ #define StatusFilePath(path, xlog, suffix) \
snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix) snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix)
#define BackupHistoryFileName(fname, tli, log, seg, offset) \ #define BackupHistoryFileName(fname, tli, logSegNo, offset) \
snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, log, seg, offset) snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, \
(uint32) ((logSegNo) / XLogSegmentsPerXLogId), \
(uint32) ((logSegNo) % XLogSegmentsPerXLogId), offset)
#define BackupHistoryFilePath(path, tli, log, seg, offset) \ #define BackupHistoryFilePath(path, tli, logSegNo, offset) \
snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, log, seg, offset) snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, \
(uint32) ((logSegNo) / XLogSegmentsPerXLogId), \
(uint32) ((logSegNo) % XLogSegmentsPerXLogId), offset)
/* /*
......
...@@ -61,16 +61,16 @@ typedef struct XLogRecPtr ...@@ -61,16 +61,16 @@ typedef struct XLogRecPtr
*/ */
#define XLByteAdvance(recptr, nbytes) \ #define XLByteAdvance(recptr, nbytes) \
do { \ do { \
if (recptr.xrecoff + nbytes >= XLogFileSize) \ uint32 oldxrecoff = (recptr).xrecoff; \
{ \ (recptr).xrecoff += nbytes; \
recptr.xlogid += 1; \ if ((recptr).xrecoff < oldxrecoff) \
recptr.xrecoff \ (recptr).xlogid += 1; /* xrecoff wrapped around */ \
= recptr.xrecoff + nbytes - XLogFileSize; \
} \
else \
recptr.xrecoff += nbytes; \
} while (0) } while (0)
/*
* XLogSegNo - physical log file sequence number.
*/
typedef uint64 XLogSegNo;
/* /*
* TimeLineID (TLI) - identifies different database histories to prevent * TimeLineID (TLI) - identifies different database histories to prevent
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment