77 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88 * Portions Copyright (c) 1994, Regents of the University of California
99 *
10- * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.59 2001/03/16 05:44:33 tgl Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.60 2001/03/17 20:54:13 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
8686/* Max time to wait to acquire XLog activity locks */
8787#define XLOG_LOCK_TIMEOUT (5*60*1000000) /* 5 minutes */
8888/* Max time to wait to acquire checkpoint lock */
89- #define CHECKPOINT_LOCK_TIMEOUT (10 *60*1000000) /* 10 minutes */
89+ #define CHECKPOINT_LOCK_TIMEOUT (20 *60*1000000) /* 20 minutes */
9090
9191/* User-settable parameters */
9292int CheckPointSegments = 3 ;
@@ -335,10 +335,6 @@ static ControlFileData *ControlFile = NULL;
335335 snprintf(path, MAXPGPATH, "%s%c%08X%08X", \
336336 XLogDir, SEP_CHAR, log, seg)
337337
338- #define XLogTempFileName (path , log , seg ) \
339- snprintf(path, MAXPGPATH, "%s%cT%08X%08X", \
340- XLogDir, SEP_CHAR, log, seg)
341-
342338#define PrevBufIdx (idx ) \
343339 (((idx) == 0) ? XLogCtl->XLogCacheBlck : ((idx) - 1))
344340
@@ -401,7 +397,8 @@ static bool InRedo = false;
401397
402398static bool AdvanceXLInsertBuffer (void );
403399static void XLogWrite (XLogwrtRqst WriteRqst );
404- static int XLogFileInit (uint32 log , uint32 seg , bool * usexistent );
400+ static int XLogFileInit (uint32 log , uint32 seg ,
401+ bool * use_existent , bool use_lock );
405402static int XLogFileOpen (uint32 log , uint32 seg , bool econt );
406403static void PreallocXlogFiles (XLogRecPtr endptr );
407404static void MoveOfflineLogs (uint32 log , uint32 seg );
@@ -960,7 +957,7 @@ XLogWrite(XLogwrtRqst WriteRqst)
960957 XLogCtlWrite * Write = & XLogCtl -> Write ;
961958 char * from ;
962959 bool ispartialpage ;
963- bool usexistent ;
960+ bool use_existent ;
964961
965962 /* Update local LogwrtResult (caller probably did this already, but...) */
966963 LogwrtResult = Write -> LogwrtResult ;
@@ -994,41 +991,42 @@ XLogWrite(XLogwrtRqst WriteRqst)
994991 }
995992 XLByteToPrevSeg (LogwrtResult .Write , openLogId , openLogSeg );
996993
997- /* create/use new log file; need lock in case creating */
998- SpinAcquire ( ControlFileLockId ) ;
999- usexistent = true;
1000- openLogFile = XLogFileInit ( openLogId , openLogSeg , & usexistent );
994+ /* create/use new log file */
995+ use_existent = true ;
996+ openLogFile = XLogFileInit ( openLogId , openLogSeg ,
997+ & use_existent , true );
1001998 openLogOff = 0 ;
999+
1000+ if (!use_existent ) /* there was no precreated file */
1001+ elog (LOG , "XLogWrite: new log file created - "
1002+ "consider increasing WAL_FILES" );
1003+
10021004 /* update pg_control, unless someone else already did */
1005+ SpinAcquire (ControlFileLockId );
10031006 if (ControlFile -> logId != openLogId ||
10041007 ControlFile -> logSeg != openLogSeg + 1 )
10051008 {
10061009 ControlFile -> logId = openLogId ;
10071010 ControlFile -> logSeg = openLogSeg + 1 ;
10081011 ControlFile -> time = time (NULL );
10091012 UpdateControlFile ();
1013+ /*
1014+ * Signal postmaster to start a checkpoint if it's been too
1015+ * long since the last one. (We look at local copy of
1016+ * RedoRecPtr which might be a little out of date, but should
1017+ * be close enough for this purpose.)
1018+ */
1019+ if (IsUnderPostmaster &&
1020+ (openLogId != RedoRecPtr .xlogid ||
1021+ openLogSeg >= (RedoRecPtr .xrecoff / XLogSegSize ) +
1022+ (uint32 ) CheckPointSegments ))
1023+ {
1024+ if (XLOG_DEBUG )
1025+ fprintf (stderr , "XLogWrite: time for a checkpoint, signaling postmaster\n" );
1026+ kill (getppid (), SIGUSR1 );
1027+ }
10101028 }
10111029 SpinRelease (ControlFileLockId );
1012-
1013- if (!usexistent ) /* there was no precreated file */
1014- elog (LOG , "XLogWrite: new log file created - "
1015- "consider increasing WAL_FILES" );
1016-
1017- /*
1018- * Signal postmaster to start a checkpoint if it's been too
1019- * long since the last one. (We look at local copy of RedoRecPtr
1020- * which might be a little out of date, but should be close enough
1021- * for this purpose.)
1022- */
1023- if (IsUnderPostmaster &&
1024- (openLogId != RedoRecPtr .xlogid ||
1025- openLogSeg >= (RedoRecPtr .xrecoff / XLogSegSize ) +
1026- (uint32 ) CheckPointSegments ))
1027- {
1028- if (XLOG_DEBUG )
1029- fprintf (stderr , "XLogWrite: time for a checkpoint, signaling postmaster\n" );
1030- kill (getppid (), SIGUSR1 );
1031- }
10321030 }
10331031
10341032 if (openLogFile < 0 )
@@ -1230,14 +1228,28 @@ XLogFlush(XLogRecPtr record)
12301228/*
12311229 * Create a new XLOG file segment, or open a pre-existing one.
12321230 *
1231+ * log, seg: identify segment to be created/opened.
1232+ *
1233+ * *use_existent: if TRUE, OK to use a pre-existing file (else, any
1234+ * pre-existing file will be deleted). On return, TRUE if a pre-existing
1235+ * file was used.
1236+ *
1237+ * use_lock: if TRUE, acquire ControlFileLock spinlock while moving file into
1238+ * place. This should be TRUE except during bootstrap log creation. The
1239+ * caller must *not* hold the spinlock at call.
1240+ *
12331241 * Returns FD of opened file.
12341242 */
12351243static int
1236- XLogFileInit (uint32 log , uint32 seg , bool * usexistent )
1244+ XLogFileInit (uint32 log , uint32 seg ,
1245+ bool * use_existent , bool use_lock )
12371246{
12381247 char path [MAXPGPATH ];
1239- char tpath [MAXPGPATH ];
1248+ char tmppath [MAXPGPATH ];
1249+ char targpath [MAXPGPATH ];
12401250 char zbuffer [BLCKSZ ];
1251+ uint32 targlog ,
1252+ targseg ;
12411253 int fd ;
12421254 int nbytes ;
12431255
@@ -1246,7 +1258,7 @@ XLogFileInit(uint32 log, uint32 seg, bool *usexistent)
12461258 /*
12471259 * Try to use existent file (checkpoint maker may have created it already)
12481260 */
1249- if (* usexistent )
1261+ if (* use_existent )
12501262 {
12511263 fd = BasicOpenFile (path , O_RDWR | PG_BINARY | XLOG_SYNC_BIT ,
12521264 S_IRUSR | S_IWUSR );
@@ -1258,20 +1270,24 @@ XLogFileInit(uint32 log, uint32 seg, bool *usexistent)
12581270 }
12591271 else
12601272 return (fd );
1261- /* Set flag to tell caller there was no existent file */
1262- * usexistent = false;
12631273 }
12641274
1265- XLogTempFileName (tpath , log , seg );
1266- unlink (tpath );
1267- unlink (path );
1275+ /*
1276+ * Initialize an empty (all zeroes) segment. NOTE: it is possible that
1277+ * another process is doing the same thing. If so, we will end up
1278+ * pre-creating an extra log segment. That seems OK, and better than
1279+ * holding the spinlock throughout this lengthy process.
1280+ */
1281+ snprintf (tmppath , MAXPGPATH , "%s%cxlogtemp.%d" ,
1282+ XLogDir , SEP_CHAR , (int ) getpid ());
1283+
1284+ unlink (tmppath );
12681285
12691286 /* do not use XLOG_SYNC_BIT here --- want to fsync only at end of fill */
1270- fd = BasicOpenFile (tpath , O_RDWR | O_CREAT | O_EXCL | PG_BINARY ,
1287+ fd = BasicOpenFile (tmppath , O_RDWR | O_CREAT | O_EXCL | PG_BINARY ,
12711288 S_IRUSR | S_IWUSR );
12721289 if (fd < 0 )
1273- elog (STOP , "InitCreate(logfile %u seg %u) failed: %m" ,
1274- log , seg );
1290+ elog (STOP , "InitCreate(%s) failed: %m" , tmppath );
12751291
12761292 /*
12771293 * Zero-fill the file. We have to do this the hard way to ensure that
@@ -1290,36 +1306,73 @@ XLogFileInit(uint32 log, uint32 seg, bool *usexistent)
12901306 int save_errno = errno ;
12911307
12921308 /* If we fail to make the file, delete it to release disk space */
1293- unlink (tpath );
1309+ unlink (tmppath );
12941310 errno = save_errno ;
12951311
1296- elog (STOP , "ZeroFill(logfile %u seg %u) failed: %m" ,
1297- log , seg );
1312+ elog (STOP , "ZeroFill(%s) failed: %m" , tmppath );
12981313 }
12991314 }
13001315
13011316 if (pg_fsync (fd ) != 0 )
1302- elog (STOP , "fsync(logfile %u seg %u) failed: %m" ,
1303- log , seg );
1317+ elog (STOP , "fsync(%s) failed: %m" , tmppath );
13041318
13051319 close (fd );
13061320
13071321 /*
1308- * Prefer link() to rename() here just to be sure that we don't overwrite
1309- * an existing logfile. However, there shouldn't be one, so rename()
1310- * is an acceptable substitute except for the truly paranoid.
1322+ * Now move the segment into place with its final name. We want to be
1323+ * sure that only one process does this at a time.
1324+ */
1325+ if (use_lock )
1326+ SpinAcquire (ControlFileLockId );
1327+
1328+ /*
1329+ * If caller didn't want to use a pre-existing file, get rid of any
1330+ * pre-existing file. Otherwise, cope with possibility that someone
1331+ * else has created the file while we were filling ours: if so, use
1332+ * ours to pre-create a future log segment.
1333+ */
1334+ targlog = log ;
1335+ targseg = seg ;
1336+ strcpy (targpath , path );
1337+
1338+ if (! * use_existent )
1339+ {
1340+ unlink (targpath );
1341+ }
1342+ else
1343+ {
1344+ while ((fd = BasicOpenFile (targpath , O_RDWR | PG_BINARY ,
1345+ S_IRUSR | S_IWUSR )) >= 0 )
1346+ {
1347+ close (fd );
1348+ NextLogSeg (targlog , targseg );
1349+ XLogFileName (targpath , targlog , targseg );
1350+ }
1351+ }
1352+
1353+ /*
1354+ * Prefer link() to rename() here just to be really sure that we don't
1355+ * overwrite an existing logfile. However, there shouldn't be one, so
1356+ * rename() is an acceptable substitute except for the truly paranoid.
13111357 */
13121358#ifndef __BEOS__
1313- if (link (tpath , path ) < 0 )
1359+ if (link (tmppath , targpath ) < 0 )
13141360 elog (STOP , "InitRelink(logfile %u seg %u) failed: %m" ,
1315- log , seg );
1316- unlink (tpath );
1361+ targlog , targseg );
1362+ unlink (tmppath );
13171363#else
1318- if (rename (tpath , path ) < 0 )
1364+ if (rename (tmppath , targpath ) < 0 )
13191365 elog (STOP , "InitRelink(logfile %u seg %u) failed: %m" ,
1320- log , seg );
1366+ targlog , targseg );
13211367#endif
13221368
1369+ if (use_lock )
1370+ SpinRelease (ControlFileLockId );
1371+
1372+ /* Set flag to tell caller there was no existent file */
1373+ * use_existent = false;
1374+
1375+ /* Now open original target segment (might not be file I just made) */
13231376 fd = BasicOpenFile (path , O_RDWR | PG_BINARY | XLOG_SYNC_BIT ,
13241377 S_IRUSR | S_IWUSR );
13251378 if (fd < 0 )
@@ -1367,39 +1420,27 @@ PreallocXlogFiles(XLogRecPtr endptr)
13671420 uint32 _logId ;
13681421 uint32 _logSeg ;
13691422 int lf ;
1370- bool usexistent ;
1371- struct timeval delay ;
1423+ bool use_existent ;
13721424 int i ;
13731425
13741426 XLByteToPrevSeg (endptr , _logId , _logSeg );
13751427 if (XLOGfiles > 0 )
13761428 {
13771429 for (i = 1 ; i <= XLOGfiles ; i ++ )
13781430 {
1379- usexistent = true;
13801431 NextLogSeg (_logId , _logSeg );
1381- SpinAcquire ( ControlFileLockId ) ;
1382- lf = XLogFileInit (_logId , _logSeg , & usexistent );
1432+ use_existent = true ;
1433+ lf = XLogFileInit (_logId , _logSeg , & use_existent , true );
13831434 close (lf );
1384- SpinRelease (ControlFileLockId );
1385- /*
1386- * Give up ControlFileLockId for 1/50 sec to let other
1387- * backends switch to new log file in XLogWrite()
1388- */
1389- delay .tv_sec = 0 ;
1390- delay .tv_usec = 20000 ;
1391- (void ) select (0 , NULL , NULL , NULL , & delay );
13921435 }
13931436 }
13941437 else if ((endptr .xrecoff - 1 ) % XLogSegSize >=
13951438 (uint32 ) (0.75 * XLogSegSize ))
13961439 {
1397- usexistent = true;
13981440 NextLogSeg (_logId , _logSeg );
1399- SpinAcquire ( ControlFileLockId ) ;
1400- lf = XLogFileInit (_logId , _logSeg , & usexistent );
1441+ use_existent = true ;
1442+ lf = XLogFileInit (_logId , _logSeg , & use_existent , true );
14011443 close (lf );
1402- SpinRelease (ControlFileLockId );
14031444 }
14041445}
14051446
@@ -2103,7 +2144,7 @@ BootStrapXLOG(void)
21032144 char * buffer ;
21042145 XLogPageHeader page ;
21052146 XLogRecord * record ;
2106- bool usexistent = false ;
2147+ bool use_existent ;
21072148 crc64 crc ;
21082149
21092150 /* Use malloc() to ensure buffer is MAXALIGNED */
@@ -2144,7 +2185,8 @@ BootStrapXLOG(void)
21442185 FIN_CRC64 (crc );
21452186 record -> xl_crc = crc ;
21462187
2147- openLogFile = XLogFileInit (0 , 0 , & usexistent );
2188+ use_existent = false;
2189+ openLogFile = XLogFileInit (0 , 0 , & use_existent , false);
21482190
21492191 if (write (openLogFile , buffer , BLCKSZ ) != BLCKSZ )
21502192 elog (STOP , "BootStrapXLOG failed to write logfile: %m" );
0 commit comments