* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.59 2001/03/16 05:44:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.60 2001/03/17 20:54:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* Max time to wait to acquire XLog activity locks */
#define XLOG_LOCK_TIMEOUT (5*60*1000000) /* 5 minutes */
/* Max time to wait to acquire checkpoint lock */
-#define CHECKPOINT_LOCK_TIMEOUT (10*60*1000000) /* 10 minutes */
+#define CHECKPOINT_LOCK_TIMEOUT (20*60*1000000) /* 20 minutes */
/* User-settable parameters */
int CheckPointSegments = 3;
snprintf(path, MAXPGPATH, "%s%c%08X%08X", \
XLogDir, SEP_CHAR, log, seg)
-#define XLogTempFileName(path, log, seg) \
- snprintf(path, MAXPGPATH, "%s%cT%08X%08X", \
- XLogDir, SEP_CHAR, log, seg)
-
#define PrevBufIdx(idx) \
(((idx) == 0) ? XLogCtl->XLogCacheBlck : ((idx) - 1))
static bool AdvanceXLInsertBuffer(void);
static void XLogWrite(XLogwrtRqst WriteRqst);
-static int XLogFileInit(uint32 log, uint32 seg, bool *usexistent);
+static int XLogFileInit(uint32 log, uint32 seg,
+ bool *use_existent, bool use_lock);
static int XLogFileOpen(uint32 log, uint32 seg, bool econt);
static void PreallocXlogFiles(XLogRecPtr endptr);
static void MoveOfflineLogs(uint32 log, uint32 seg);
XLogCtlWrite *Write = &XLogCtl->Write;
char *from;
bool ispartialpage;
- bool usexistent;
+ bool use_existent;
/* Update local LogwrtResult (caller probably did this already, but...) */
LogwrtResult = Write->LogwrtResult;
}
XLByteToPrevSeg(LogwrtResult.Write, openLogId, openLogSeg);
- /* create/use new log file; need lock in case creating */
- SpinAcquire(ControlFileLockId);
- usexistent = true;
- openLogFile = XLogFileInit(openLogId, openLogSeg, &usexistent);
+ /* create/use new log file */
+ use_existent = true;
+ openLogFile = XLogFileInit(openLogId, openLogSeg,
+ &use_existent, true);
openLogOff = 0;
+
+ if (!use_existent) /* there was no precreated file */
+ elog(LOG, "XLogWrite: new log file created - "
+ "consider increasing WAL_FILES");
+
/* update pg_control, unless someone else already did */
+ SpinAcquire(ControlFileLockId);
if (ControlFile->logId != openLogId ||
ControlFile->logSeg != openLogSeg + 1)
{
ControlFile->logSeg = openLogSeg + 1;
ControlFile->time = time(NULL);
UpdateControlFile();
+ /*
+ * Signal postmaster to start a checkpoint if it's been too
+ * long since the last one. (We look at local copy of
+ * RedoRecPtr which might be a little out of date, but should
+ * be close enough for this purpose.)
+ */
+ if (IsUnderPostmaster &&
+ (openLogId != RedoRecPtr.xlogid ||
+ openLogSeg >= (RedoRecPtr.xrecoff / XLogSegSize) +
+ (uint32) CheckPointSegments))
+ {
+ if (XLOG_DEBUG)
+ fprintf(stderr, "XLogWrite: time for a checkpoint, signaling postmaster\n");
+ kill(getppid(), SIGUSR1);
+ }
}
SpinRelease(ControlFileLockId);
-
- if (!usexistent) /* there was no precreated file */
- elog(LOG, "XLogWrite: new log file created - "
- "consider increasing WAL_FILES");
-
- /*
- * Signal postmaster to start a checkpoint if it's been too
- * long since the last one. (We look at local copy of RedoRecPtr
- * which might be a little out of date, but should be close enough
- * for this purpose.)
- */
- if (IsUnderPostmaster &&
- (openLogId != RedoRecPtr.xlogid ||
- openLogSeg >= (RedoRecPtr.xrecoff / XLogSegSize) +
- (uint32) CheckPointSegments))
- {
- if (XLOG_DEBUG)
- fprintf(stderr, "XLogWrite: time for a checkpoint, signaling postmaster\n");
- kill(getppid(), SIGUSR1);
- }
}
if (openLogFile < 0)
/*
* Create a new XLOG file segment, or open a pre-existing one.
*
+ * log, seg: identify segment to be created/opened.
+ *
+ * *use_existent: if TRUE, OK to use a pre-existing file (else, any
+ * pre-existing file will be deleted). On return, TRUE if a pre-existing
+ * file was used.
+ *
+ * use_lock: if TRUE, acquire ControlFileLock spinlock while moving file into
+ * place. This should be TRUE except during bootstrap log creation. The
+ * caller must *not* hold the spinlock at call.
+ *
* Returns FD of opened file.
*/
static int
-XLogFileInit(uint32 log, uint32 seg, bool *usexistent)
+XLogFileInit(uint32 log, uint32 seg,
+ bool *use_existent, bool use_lock)
{
char path[MAXPGPATH];
- char tpath[MAXPGPATH];
+ char tmppath[MAXPGPATH];
+ char targpath[MAXPGPATH];
char zbuffer[BLCKSZ];
+ uint32 targlog,
+ targseg;
int fd;
int nbytes;
/*
* Try to use existent file (checkpoint maker may have created it already)
*/
- if (*usexistent)
+ if (*use_existent)
{
fd = BasicOpenFile(path, O_RDWR | PG_BINARY | XLOG_SYNC_BIT,
S_IRUSR | S_IWUSR);
}
else
return(fd);
- /* Set flag to tell caller there was no existent file */
- *usexistent = false;
}
- XLogTempFileName(tpath, log, seg);
- unlink(tpath);
- unlink(path);
+ /*
+ * Initialize an empty (all zeroes) segment. NOTE: it is possible that
+ * another process is doing the same thing. If so, we will end up
+ * pre-creating an extra log segment. That seems OK, and better than
+ * holding the spinlock throughout this lengthy process.
+ */
+ snprintf(tmppath, MAXPGPATH, "%s%cxlogtemp.%d",
+ XLogDir, SEP_CHAR, (int) getpid());
+
+ unlink(tmppath);
/* do not use XLOG_SYNC_BIT here --- want to fsync only at end of fill */
- fd = BasicOpenFile(tpath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
+ fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
S_IRUSR | S_IWUSR);
if (fd < 0)
- elog(STOP, "InitCreate(logfile %u seg %u) failed: %m",
- log, seg);
+ elog(STOP, "InitCreate(%s) failed: %m", tmppath);
/*
* Zero-fill the file. We have to do this the hard way to ensure that
int save_errno = errno;
/* If we fail to make the file, delete it to release disk space */
- unlink(tpath);
+ unlink(tmppath);
errno = save_errno;
- elog(STOP, "ZeroFill(logfile %u seg %u) failed: %m",
- log, seg);
+ elog(STOP, "ZeroFill(%s) failed: %m", tmppath);
}
}
if (pg_fsync(fd) != 0)
- elog(STOP, "fsync(logfile %u seg %u) failed: %m",
- log, seg);
+ elog(STOP, "fsync(%s) failed: %m", tmppath);
close(fd);
/*
- * Prefer link() to rename() here just to be sure that we don't overwrite
- * an existing logfile. However, there shouldn't be one, so rename()
- * is an acceptable substitute except for the truly paranoid.
+ * Now move the segment into place with its final name. We want to be
+ * sure that only one process does this at a time.
+ */
+ if (use_lock)
+ SpinAcquire(ControlFileLockId);
+
+ /*
+ * If caller didn't want to use a pre-existing file, get rid of any
+ * pre-existing file. Otherwise, cope with possibility that someone
+ * else has created the file while we were filling ours: if so, use
+ * ours to pre-create a future log segment.
+ */
+ targlog = log;
+ targseg = seg;
+ strcpy(targpath, path);
+
+ if (! *use_existent)
+ {
+ unlink(targpath);
+ }
+ else
+ {
+ while ((fd = BasicOpenFile(targpath, O_RDWR | PG_BINARY,
+ S_IRUSR | S_IWUSR)) >= 0)
+ {
+ close(fd);
+ NextLogSeg(targlog, targseg);
+ XLogFileName(targpath, targlog, targseg);
+ }
+ }
+
+ /*
+ * Prefer link() to rename() here just to be really sure that we don't
+ * overwrite an existing logfile. However, there shouldn't be one, so
+ * rename() is an acceptable substitute except for the truly paranoid.
*/
#ifndef __BEOS__
- if (link(tpath, path) < 0)
+ if (link(tmppath, targpath) < 0)
elog(STOP, "InitRelink(logfile %u seg %u) failed: %m",
- log, seg);
- unlink(tpath);
+ targlog, targseg);
+ unlink(tmppath);
#else
- if (rename(tpath, path) < 0)
+ if (rename(tmppath, targpath) < 0)
elog(STOP, "InitRelink(logfile %u seg %u) failed: %m",
- log, seg);
+ targlog, targseg);
#endif
+ if (use_lock)
+ SpinRelease(ControlFileLockId);
+
+ /* Set flag to tell caller there was no existent file */
+ *use_existent = false;
+
+ /* Now open original target segment (might not be file I just made) */
fd = BasicOpenFile(path, O_RDWR | PG_BINARY | XLOG_SYNC_BIT,
S_IRUSR | S_IWUSR);
if (fd < 0)
uint32 _logId;
uint32 _logSeg;
int lf;
- bool usexistent;
- struct timeval delay;
+ bool use_existent;
int i;
XLByteToPrevSeg(endptr, _logId, _logSeg);
{
for (i = 1; i <= XLOGfiles; i++)
{
- usexistent = true;
NextLogSeg(_logId, _logSeg);
- SpinAcquire(ControlFileLockId);
- lf = XLogFileInit(_logId, _logSeg, &usexistent);
+ use_existent = true;
+ lf = XLogFileInit(_logId, _logSeg, &use_existent, true);
close(lf);
- SpinRelease(ControlFileLockId);
- /*
- * Give up ControlFileLockId for 1/50 sec to let other
- * backends switch to new log file in XLogWrite()
- */
- delay.tv_sec = 0;
- delay.tv_usec = 20000;
- (void) select(0, NULL, NULL, NULL, &delay);
}
}
else if ((endptr.xrecoff - 1) % XLogSegSize >=
(uint32) (0.75 * XLogSegSize))
{
- usexistent = true;
NextLogSeg(_logId, _logSeg);
- SpinAcquire(ControlFileLockId);
- lf = XLogFileInit(_logId, _logSeg, &usexistent);
+ use_existent = true;
+ lf = XLogFileInit(_logId, _logSeg, &use_existent, true);
close(lf);
- SpinRelease(ControlFileLockId);
}
}
char *buffer;
XLogPageHeader page;
XLogRecord *record;
- bool usexistent = false;
+ bool use_existent;
crc64 crc;
/* Use malloc() to ensure buffer is MAXALIGNED */
FIN_CRC64(crc);
record->xl_crc = crc;
- openLogFile = XLogFileInit(0, 0, &usexistent);
+ use_existent = false;
+ openLogFile = XLogFileInit(0, 0, &use_existent, false);
if (write(openLogFile, buffer, BLCKSZ) != BLCKSZ)
elog(STOP, "BootStrapXLOG failed to write logfile: %m");