mirror of
https://github.com/postgres/postgres.git
synced 2025-06-29 10:41:53 +03:00
New CHECKPOINT command.
Auto removing of offline log files and creating new file at checkpoint time.
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.23 2000/11/03 11:39:35 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.24 2000/11/05 22:50:19 vadim Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -16,6 +16,8 @@
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
@ -48,7 +50,10 @@ StartUpID ThisStartUpID = 0;
|
||||
|
||||
int XLOG_DEBUG = 1;
|
||||
|
||||
/* To read/update control file and create new log file */
|
||||
SPINLOCK ControlFileLockId;
|
||||
|
||||
/* To generate new xid */
|
||||
SPINLOCK XidGenLockId;
|
||||
|
||||
extern VariableCache ShmemVariableCache;
|
||||
@ -91,19 +96,20 @@ typedef struct XLogCtlWrite
|
||||
|
||||
typedef struct XLogCtlData
|
||||
{
|
||||
XLogCtlInsert Insert;
|
||||
XLgwrRqst LgwrRqst;
|
||||
XLgwrResult LgwrResult;
|
||||
XLogCtlWrite Write;
|
||||
char *pages;
|
||||
XLogRecPtr *xlblocks; /* 1st byte ptr-s + BLCKSZ */
|
||||
uint32 XLogCacheByte;
|
||||
uint32 XLogCacheBlck;
|
||||
StartUpID ThisStartUpID;
|
||||
XLogCtlInsert Insert;
|
||||
XLgwrRqst LgwrRqst;
|
||||
XLgwrResult LgwrResult;
|
||||
XLogCtlWrite Write;
|
||||
char *pages;
|
||||
XLogRecPtr *xlblocks; /* 1st byte ptr-s + BLCKSZ */
|
||||
uint32 XLogCacheByte;
|
||||
uint32 XLogCacheBlck;
|
||||
StartUpID ThisStartUpID;
|
||||
#ifdef HAS_TEST_AND_SET
|
||||
slock_t insert_lck;
|
||||
slock_t info_lck;
|
||||
slock_t lgwr_lck;
|
||||
slock_t insert_lck;
|
||||
slock_t info_lck;
|
||||
slock_t lgwr_lck;
|
||||
slock_t chkp_lck; /* checkpoint lock */
|
||||
#endif
|
||||
} XLogCtlData;
|
||||
|
||||
@ -133,6 +139,7 @@ typedef struct ControlFileData
|
||||
uint32 blcksz; /* block size for this DB */
|
||||
uint32 relseg_size; /* blocks per segment of large relation */
|
||||
uint32 catalog_version_no; /* internal version number */
|
||||
char archdir[MAXPGPATH]; /* where to move offline log files */
|
||||
|
||||
/*
|
||||
* MORE DATA FOLLOWS AT THE END OF THIS STRUCTURE - locations of data
|
||||
@ -170,6 +177,10 @@ typedef struct CheckPoint
|
||||
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(curridx) \
|
||||
((curridx == 0) ? XLogCtl->XLogCacheBlck : (curridx - 1))
|
||||
|
||||
@ -198,7 +209,7 @@ typedef struct CheckPoint
|
||||
|
||||
static void GetFreeXLBuffer(void);
|
||||
static void XLogWrite(char *buffer);
|
||||
static int XLogFileInit(uint32 log, uint32 seg);
|
||||
static int XLogFileInit(uint32 log, uint32 seg, bool *usexistent);
|
||||
static int XLogFileOpen(uint32 log, uint32 seg, bool econt);
|
||||
static XLogRecord *ReadRecord(XLogRecPtr *RecPtr, char *buffer);
|
||||
static char *str_time(time_t tnow);
|
||||
@ -672,6 +683,7 @@ XLogWrite(char *buffer)
|
||||
char *from;
|
||||
uint32 wcnt = 0;
|
||||
int i = 0;
|
||||
bool usexistent;
|
||||
|
||||
for (; XLByteLT(LgwrResult.Write, LgwrRqst.Write);)
|
||||
{
|
||||
@ -710,13 +722,18 @@ XLogWrite(char *buffer)
|
||||
logId = LgwrResult.Write.xlogid;
|
||||
logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize;
|
||||
logOff = 0;
|
||||
logFile = XLogFileInit(logId, logSeg);
|
||||
SpinAcquire(ControlFileLockId);
|
||||
/* create/use new log file */
|
||||
usexistent = true;
|
||||
logFile = XLogFileInit(logId, logSeg, &usexistent);
|
||||
ControlFile->logId = logId;
|
||||
ControlFile->logSeg = logSeg + 1;
|
||||
ControlFile->time = time(NULL);
|
||||
UpdateControlFile();
|
||||
SpinRelease(ControlFileLockId);
|
||||
if (!usexistent) /* there was no file */
|
||||
elog(LOG, "XLogWrite: had to create new log file - "
|
||||
"you probably should do checkpoints more often");
|
||||
}
|
||||
|
||||
if (logFile < 0)
|
||||
@ -780,17 +797,39 @@ XLogWrite(char *buffer)
|
||||
}
|
||||
|
||||
static int
|
||||
XLogFileInit(uint32 log, uint32 seg)
|
||||
XLogFileInit(uint32 log, uint32 seg, bool *usexistent)
|
||||
{
|
||||
char path[MAXPGPATH];
|
||||
char tpath[MAXPGPATH];
|
||||
int fd;
|
||||
|
||||
XLogFileName(path, log, seg);
|
||||
|
||||
/*
|
||||
* Try to use existent file (checkpoint maker
|
||||
* creates it sometime).
|
||||
*/
|
||||
if (*usexistent)
|
||||
{
|
||||
fd = BasicOpenFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
elog(STOP, "InitOpen(logfile %u seg %u) failed: %d",
|
||||
logId, logSeg, errno);
|
||||
}
|
||||
else
|
||||
return(fd);
|
||||
*usexistent = false;
|
||||
}
|
||||
|
||||
XLogTempFileName(tpath, log, seg);
|
||||
unlink(tpath);
|
||||
unlink(path);
|
||||
|
||||
fd = BasicOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, S_IRUSR | S_IWUSR);
|
||||
fd = BasicOpenFile(tpath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0)
|
||||
elog(STOP, "Init(logfile %u seg %u) failed: %d",
|
||||
elog(STOP, "InitCreate(logfile %u seg %u) failed: %d",
|
||||
logId, logSeg, errno);
|
||||
|
||||
if (lseek(fd, XLogSegSize - 1, SEEK_SET) != (off_t) (XLogSegSize - 1))
|
||||
@ -809,6 +848,15 @@ XLogFileInit(uint32 log, uint32 seg)
|
||||
elog(STOP, "Lseek(logfile %u seg %u off %u) failed: %d",
|
||||
log, seg, 0, errno);
|
||||
|
||||
close(fd);
|
||||
link(tpath, path);
|
||||
unlink(tpath);
|
||||
|
||||
fd = BasicOpenFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0)
|
||||
elog(STOP, "InitReopen(logfile %u seg %u) failed: %d",
|
||||
logId, logSeg, errno);
|
||||
|
||||
return (fd);
|
||||
}
|
||||
|
||||
@ -837,6 +885,49 @@ XLogFileOpen(uint32 log, uint32 seg, bool econt)
|
||||
return (fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* (Re)move offline log files older or equal to passwd one
|
||||
*/
|
||||
static void
|
||||
MoveOfflineLogs(char *archdir, uint32 _logId, uint32 _logSeg)
|
||||
{
|
||||
DIR *xldir;
|
||||
struct dirent *xlde;
|
||||
char lastoff[32];
|
||||
char path[MAXPGPATH];
|
||||
|
||||
Assert(archdir[0] == 0); /* ! implemented yet */
|
||||
|
||||
xldir = opendir(XLogDir);
|
||||
if (xldir == NULL)
|
||||
elog(STOP, "MoveOfflineLogs: cannot open xlog dir: %d", errno);
|
||||
|
||||
sprintf(lastoff, "%08X%08X", _logId, _logSeg);
|
||||
|
||||
errno = 0;
|
||||
while ((xlde = readdir(xldir)) != NULL)
|
||||
{
|
||||
if (strlen(xlde->d_name) != 16 ||
|
||||
strspn(xlde->d_name, "0123456789ABCDEF") != 16)
|
||||
continue;
|
||||
if (strcmp(xlde->d_name, lastoff) > 0)
|
||||
{
|
||||
elog(LOG, "MoveOfflineLogs: skip %s", xlde->d_name);
|
||||
errno = 0;
|
||||
continue;
|
||||
}
|
||||
elog(LOG, "MoveOfflineLogs: %s %s", (archdir[0]) ?
|
||||
"archive" : "remove", xlde->d_name);
|
||||
sprintf(path, "%s%c%s", XLogDir, SEP_CHAR, xlde->d_name);
|
||||
if (archdir[0] != 0)
|
||||
unlink(path);
|
||||
errno = 0;
|
||||
}
|
||||
if (errno)
|
||||
elog(STOP, "MoveOfflineLogs: cannot read xlog dir: %d", errno);
|
||||
closedir(xldir);
|
||||
}
|
||||
|
||||
static XLogRecord *
|
||||
ReadRecord(XLogRecPtr *RecPtr, char *buffer)
|
||||
{
|
||||
@ -1183,6 +1274,7 @@ BootStrapXLOG()
|
||||
int fd;
|
||||
char buffer[BLCKSZ];
|
||||
CheckPoint checkPoint;
|
||||
bool usexistent = false;
|
||||
|
||||
#ifdef XLOG
|
||||
XLogPageHeader page = (XLogPageHeader) buffer;
|
||||
@ -1217,7 +1309,7 @@ BootStrapXLOG()
|
||||
record->xl_rmid = RM_XLOG_ID;
|
||||
memcpy((char *) record + SizeOfXLogRecord, &checkPoint, sizeof(checkPoint));
|
||||
|
||||
logFile = XLogFileInit(0, 0);
|
||||
logFile = XLogFileInit(0, 0, &usexistent);
|
||||
|
||||
if (write(logFile, buffer, BLCKSZ) != BLCKSZ)
|
||||
elog(STOP, "BootStrapXLOG failed to write logfile: %d", errno);
|
||||
@ -1297,6 +1389,7 @@ StartupXLOG()
|
||||
S_INIT_LOCK(&(XLogCtl->insert_lck));
|
||||
S_INIT_LOCK(&(XLogCtl->info_lck));
|
||||
S_INIT_LOCK(&(XLogCtl->lgwr_lck));
|
||||
S_INIT_LOCK(&(XLogCtl->chkp_lck));
|
||||
|
||||
/*
|
||||
* Open/read Control file
|
||||
@ -1556,6 +1649,8 @@ ShutdownXLOG()
|
||||
elog(LOG, "Data Base System shut down at %s", str_time(time(NULL)));
|
||||
}
|
||||
|
||||
extern XLogRecPtr GetUndoRecPtr(void);
|
||||
|
||||
void
|
||||
CreateCheckPoint(bool shutdown)
|
||||
{
|
||||
@ -1565,6 +1660,21 @@ CreateCheckPoint(bool shutdown)
|
||||
XLogCtlInsert *Insert = &XLogCtl->Insert;
|
||||
uint32 freespace;
|
||||
uint16 curridx;
|
||||
uint32 _logId;
|
||||
uint32 _logSeg;
|
||||
char archdir[MAXPGPATH];
|
||||
|
||||
if (MyLastRecPtr.xrecoff != 0)
|
||||
elog(ERROR, "CreateCheckPoint: cannot be called inside transaction block");
|
||||
|
||||
while (TAS(&(XLogCtl->chkp_lck)))
|
||||
{
|
||||
struct timeval delay = {2, 0};
|
||||
|
||||
if (shutdown)
|
||||
elog(STOP, "Checkpoint lock is busy while data base is shutting down");
|
||||
(void) select(0, NULL, NULL, NULL, &delay);
|
||||
}
|
||||
|
||||
memset(&checkPoint, 0, sizeof(checkPoint));
|
||||
if (shutdown)
|
||||
@ -1579,7 +1689,7 @@ CreateCheckPoint(bool shutdown)
|
||||
/* Get REDO record ptr */
|
||||
while (TAS(&(XLogCtl->insert_lck)))
|
||||
{
|
||||
struct timeval delay = {0, 5000};
|
||||
struct timeval delay = {1, 0};
|
||||
|
||||
if (shutdown)
|
||||
elog(STOP, "XLog insert lock is busy while data base is shutting down");
|
||||
@ -1615,7 +1725,7 @@ CreateCheckPoint(bool shutdown)
|
||||
FlushBufferPool();
|
||||
|
||||
/* Get UNDO record ptr - should use oldest of PROC->logRec */
|
||||
checkPoint.undo.xrecoff = 0;
|
||||
checkPoint.undo = GetUndoRecPtr();
|
||||
|
||||
if (shutdown && checkPoint.undo.xrecoff != 0)
|
||||
elog(STOP, "Active transaction while data base is shutting down");
|
||||
@ -1633,9 +1743,35 @@ CreateCheckPoint(bool shutdown)
|
||||
SpinAcquire(ControlFileLockId);
|
||||
if (shutdown)
|
||||
ControlFile->state = DB_SHUTDOWNED;
|
||||
|
||||
#ifdef XLOG
|
||||
else /* create new log file */
|
||||
{
|
||||
if (recptr.xrecoff % XLogSegSize >=
|
||||
(uint32) (0.75 * XLogSegSize))
|
||||
{
|
||||
int lf;
|
||||
bool usexistent = true;
|
||||
|
||||
_logId = recptr.xlogid;
|
||||
_logSeg = recptr.xrecoff / XLogSegSize;
|
||||
if (_logSeg >= XLogLastSeg)
|
||||
{
|
||||
_logId++;
|
||||
_logSeg = 0;
|
||||
}
|
||||
else
|
||||
_logSeg++;
|
||||
lf = XLogFileInit(_logId, _logSeg, &usexistent);
|
||||
close(lf);
|
||||
}
|
||||
}
|
||||
|
||||
ControlFile->checkPoint = MyLastRecPtr;
|
||||
|
||||
_logId = ControlFile->logId;
|
||||
_logSeg = ControlFile->logSeg - 1;
|
||||
strcpy(archdir, ControlFile->archdir);
|
||||
|
||||
#else
|
||||
ControlFile->checkPoint.xlogid = 0;
|
||||
ControlFile->checkPoint.xrecoff = SizeOfXLogPHD;
|
||||
@ -1645,6 +1781,33 @@ CreateCheckPoint(bool shutdown)
|
||||
UpdateControlFile();
|
||||
SpinRelease(ControlFileLockId);
|
||||
|
||||
#ifdef XLOG
|
||||
/*
|
||||
* Delete offline log files. Get oldest online
|
||||
* log file from undo rec if it's valid.
|
||||
*/
|
||||
if (checkPoint.undo.xrecoff != 0)
|
||||
{
|
||||
_logId = checkPoint.undo.xlogid;
|
||||
_logSeg = checkPoint.undo.xrecoff / XLogSegSize;
|
||||
}
|
||||
if (_logId || _logSeg)
|
||||
{
|
||||
if (_logSeg)
|
||||
_logSeg--;
|
||||
else
|
||||
{
|
||||
_logId--;
|
||||
_logSeg = 0;
|
||||
}
|
||||
MoveOfflineLogs(archdir, _logId, _logSeg);
|
||||
}
|
||||
|
||||
S_UNLOCK(&(XLogCtl->chkp_lck));
|
||||
|
||||
MyLastRecPtr.xrecoff = 0; /* to avoid commit record */
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user