First step in cleaning up backend initialization code.
Fix for FATAL: now FATAL is ERROR + exit.
void UpdateControlFile(void);
int XLOGShmemSize(void);
+void XLOGShmemInit(void);
void BootStrapXLOG(void);
void StartupXLOG(void);
+void ShutdownXLOG(void);
void CreateCheckPoint(bool shutdown);
-char *XLogDir = NULL;
-char *ControlFilePath = NULL;
+char XLogDir[MAXPGPATH+1];
+char ControlFilePath[MAXPGPATH+1];
uint32 XLOGbuffers = 0;
XLogRecPtr MyLastRecPtr = {0, 0};
bool StopIfError = false;
typedef enum DBState
{
- DB_SHUTDOWNED = 1,
+ DB_STARTUP = 0,
+ DB_SHUTDOWNED,
DB_SHUTDOWNING,
DB_IN_RECOVERY,
DB_IN_PRODUCTION
} CheckPoint;
/*
- * We break each log file in 64Mb segments
+ * We break each log file in 16Mb segments
*/
-#define XLogSegSize (64*1024*1024)
+#define XLogSegSize (16*1024*1024)
#define XLogLastSeg (0xffffffff / XLogSegSize)
#define XLogFileSize (XLogLastSeg * XLogSegSize)
static int XLogFileInit(uint32 log, uint32 seg);
static int XLogFileOpen(uint32 log, uint32 seg, bool econt);
static XLogRecord *ReadRecord(XLogRecPtr *RecPtr, char *buffer);
+static char *str_time(time_t tnow);
static XLgwrResult LgwrResult = {{0, 0}, {0, 0}};
static XLgwrRqst LgwrRqst = {{0, 0}, {0, 0}};
static int logFile = -1;
static uint32 logId = 0;
static uint32 logSeg = 0;
-static off_t logOff = 0;
+static uint32 logOff = 0;
static XLogRecPtr ReadRecPtr;
static XLogRecPtr EndRecPtr;
static int readFile = -1;
static uint32 readId = 0;
static uint32 readSeg = 0;
-static off_t readOff = (off_t) -1;
+static uint32 readOff = 0;
static char readBuf[BLCKSZ];
static XLogRecord *nextRecord = NULL;
freespace -= SizeOfXLogRecord;
record = (XLogRecord*) Insert->currpos;
record->xl_prev = Insert->PrevRecord;
- record->xl_xact_prev = MyLastRecPtr;
+ if (rmid != RM_XLOG_ID)
+ record->xl_xact_prev = MyLastRecPtr;
+ else
+ {
+ record->xl_xact_prev.xlogid = 0;
+ record->xl_xact_prev.xrecoff = 0;
+ }
record->xl_xid = GetCurrentTransactionId();
record->xl_len = (len > freespace) ? freespace : len;
record->xl_info = (len > freespace) ? XLR_TO_BE_CONTINUED : 0;
RecPtr.xrecoff =
XLogCtl->xlblocks[curridx].xrecoff - BLCKSZ +
Insert->currpos - ((char*) Insert->currpage);
- if (MyLastRecPtr.xrecoff == 0)
+ if (MyLastRecPtr.xrecoff == 0 && rmid != RM_XLOG_ID)
{
SpinAcquire(SInvalLock);
MyProc->logRec = RecPtr;
{
logId = LgwrResult.Write.xlogid;
logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize;
- logOff = (off_t) 0;
+ logOff = 0;
logFile = XLogFileOpen(logId, logSeg, false);
}
}
logId = LgwrResult.Write.xlogid;
logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize;
- logOff = (off_t) 0;
+ logOff = 0;
logFile = XLogFileInit(logId, logSeg);
SpinAcquire(ControlFileLockId);
ControlFile->logId = logId;
{
logId = LgwrResult.Write.xlogid;
logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize;
- logOff = (off_t) 0;
+ logOff = 0;
logFile = XLogFileOpen(logId, logSeg, false);
}
if (logOff != (LgwrResult.Write.xrecoff - BLCKSZ) % XLogSegSize)
{
logOff = (LgwrResult.Write.xrecoff - BLCKSZ) % XLogSegSize;
- if (lseek(logFile, logOff, SEEK_SET) < 0)
+ if (lseek(logFile, (off_t)logOff, SEEK_SET) < 0)
elog(STOP, "Lseek(logfile %u seg %u off %u) failed: %d",
logId, logSeg, logOff, errno);
}
elog(STOP, "Fsync(logfile %u seg %u) failed: %d",
logId, logSeg, errno);
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ elog(STOP, "Lseek(logfile %u seg %u off %u) failed: %d",
+ log, seg, 0, errno);
+
return(fd);
}
return(fd);
}
-void
-UpdateControlFile()
-{
- int fd;
-
-tryAgain:
- fd = open(ControlFilePath, O_RDWR);
- if (fd < 0 && (errno == EMFILE || errno == ENFILE))
- {
- fd = errno;
- if (!ReleaseDataFile())
- elog(STOP, "Open(cntlfile) failed: %d (and no one data file can be closed)",
- fd);
- goto tryAgain;
- }
- if (fd < 0)
- elog(STOP, "Open(cntlfile) failed: %d", errno);
-
- if (write(fd, ControlFile, BLCKSZ) != BLCKSZ)
- elog(STOP, "Write(cntlfile) failed: %d", errno);
-
- if (fsync(fd) != 0)
- elog(STOP, "Fsync(cntlfile) failed: %d", errno);
-
- close(fd);
-
- return;
-}
-
-int
-XLOGShmemSize()
-{
- if (XLOGbuffers < MinXLOGbuffers)
- XLOGbuffers = MinXLOGbuffers;
-
- return(sizeof(XLogCtlData) + BLCKSZ * XLOGbuffers +
- sizeof(XLogRecPtr) * XLOGbuffers + BLCKSZ);
-}
-
-/*
- * This func must be called ONCE on system install
- */
-void
-BootStrapXLOG()
+static XLogRecord*
+ReadRecord(XLogRecPtr *RecPtr, char *buffer)
{
- int fd;
- char buffer[BLCKSZ];
- XLogPageHeader page = (XLogPageHeader)buffer;
- CheckPoint checkPoint;
XLogRecord *record;
+ XLogRecPtr tmpRecPtr = EndRecPtr;
+ bool nextmode = (RecPtr == NULL);
+ int emode = (nextmode) ? LOG : STOP;
+ bool noBlck = false;
- fd = open(ControlFilePath, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
- if (fd < 0)
- elog(STOP, "BootStrapXLOG failed to create control file: %d", errno);
-
- logFile = XLogFileInit(0, 0);
-
- checkPoint.redo.xlogid = 0;
- checkPoint.redo.xrecoff = SizeOfXLogPHD;
- checkPoint.undo = checkPoint.redo;
- checkPoint.nextXid = FirstTransactionId;
- checkPoint.nextOid = BootstrapObjectIdData;
-
- memset(buffer, 0, BLCKSZ);
- page->xlp_magic = XLOG_PAGE_MAGIC;
- page->xlp_info = 0;
- record = (XLogRecord*) ((char*)page + SizeOfXLogPHD);
- record->xl_prev.xlogid = 0; record->xl_prev.xrecoff = 0;
- record->xl_xact_prev = record->xl_prev;
- record->xl_xid = InvalidTransactionId;
- record->xl_len = sizeof(checkPoint);
- record->xl_info = 0;
- record->xl_rmid = RM_XLOG_ID;
- memcpy((char*)record + SizeOfXLogRecord, &checkPoint, sizeof(checkPoint));
-
- if (write(logFile, buffer, BLCKSZ) != BLCKSZ)
- elog(STOP, "BootStrapXLOG failed to write logfile: %d", errno);
-
- if (fsync(logFile) != 0)
- elog(STOP, "BootStrapXLOG failed to fsync logfile: %d", errno);
-
- close(logFile);
- logFile = -1;
-
- memset(buffer, 0, BLCKSZ);
- ControlFile = (ControlFileData*) buffer;
- ControlFile->logId = 0;
- ControlFile->logSeg = 1;
- ControlFile->checkPoint = checkPoint.redo;
- ControlFile->time = time(NULL);
- ControlFile->state = DB_SHUTDOWNED;
-
- if (write(fd, buffer, BLCKSZ) != BLCKSZ)
- elog(STOP, "BootStrapXLOG failed to write control file: %d", errno);
-
- if (fsync(fd) != 0)
- elog(STOP, "BootStrapXLOG failed to fsync control file: %d", errno);
-
- close(fd);
-
- return;
-
-}
-
-/*
- * This func must be called ONCE on system startup
- */
-void
-StartupXLOG()
-{
- XLogCtlInsert *Insert = &XLogCtl->Insert;
- CheckPoint checkPoint;
- XLogRecPtr RecPtr,
- LastRec;
- XLogRecord *record;
- char buffer[MAXLOGRECSZ+SizeOfXLogRecord];
- int fd;
- bool found;
- bool recovery = false;
- bool sie_saved = false;
-
- elog(LOG, "Starting up XLOG manager...");
-
- if (XLOGbuffers < MinXLOGbuffers)
- XLOGbuffers = MinXLOGbuffers;
-
- ControlFile = (ControlFileData*)
- ShmemInitStruct("Control File", BLCKSZ, &found);
- Assert(!found);
- XLogCtl = (XLogCtlData*)
- ShmemInitStruct("XLOG Ctl", sizeof(XLogCtlData) + BLCKSZ * XLOGbuffers +
- sizeof(XLogRecPtr) * XLOGbuffers, &found);
- Assert(!found);
-
- XLogCtl->xlblocks = (XLogRecPtr*) (((char *)XLogCtl) + sizeof(XLogCtlData));
- XLogCtl->pages = ((char *)XLogCtl->xlblocks + sizeof(XLogRecPtr) * XLOGbuffers);
- XLogCtl->XLogCacheByte = BLCKSZ * XLOGbuffers;
- XLogCtl->XLogCacheBlck = XLOGbuffers - 1;
- memset(XLogCtl->xlblocks, 0, sizeof(XLogRecPtr) * XLOGbuffers);
- XLogCtl->LgwrRqst = LgwrRqst;
- XLogCtl->LgwrResult = LgwrResult;
- XLogCtl->Insert.LgwrResult = LgwrResult;
- XLogCtl->Insert.curridx = 0;
- XLogCtl->Insert.currpage = (XLogPageHeader) (XLogCtl->pages);
- XLogCtl->Write.LgwrResult = LgwrResult;
- XLogCtl->Write.curridx = 0;
-
- /*
- * Open/read Control file
- */
-tryAgain:
- fd = open(ControlFilePath, O_RDWR);
- if (fd < 0 && (errno == EMFILE || errno == ENFILE))
+ if (nextmode)
{
- fd = errno;
- if (!ReleaseDataFile())
- elog(STOP, "Open(cntlfile) failed: %d (and no one data file can be closed)",
- fd);
- goto tryAgain;
+ RecPtr = &tmpRecPtr;
+ if (nextRecord != NULL)
+ {
+ record = nextRecord;
+ goto got_record;
+ }
+ if (tmpRecPtr.xrecoff % BLCKSZ != 0)
+ tmpRecPtr.xrecoff += (BLCKSZ - tmpRecPtr.xrecoff % BLCKSZ);
+ if (tmpRecPtr.xrecoff >= XLogFileSize)
+ {
+ (tmpRecPtr.xlogid)++;
+ tmpRecPtr.xrecoff = 0;
+ }
+ tmpRecPtr.xrecoff += SizeOfXLogPHD;
}
- if (fd < 0)
- elog(STOP, "Open(cntlfile) failed: %d", errno);
-
- if (read(fd, ControlFile, BLCKSZ) != BLCKSZ)
- elog(STOP, "Read(cntlfile) failed: %d", errno);
-
- close(fd);
-
- if (ControlFile->logSeg == 0 ||
- ControlFile->time <= 0 ||
- ControlFile->state < DB_SHUTDOWNED ||
- ControlFile->state > DB_IN_PRODUCTION ||
- ControlFile->checkPoint.xlogid == 0 ||
- ControlFile->checkPoint.xrecoff == 0)
- elog(STOP, "Control file context is broken");
+ else if (!XRecOffIsValid(RecPtr->xrecoff))
+ elog(STOP, "ReadRecord: invalid record offset in (%u, %u)",
+ RecPtr->xlogid, RecPtr->xrecoff);
- if (ControlFile->state == DB_SHUTDOWNED)
- elog(LOG, "Data Base System was properly shutdowned at %s",
- ctime(&(ControlFile->time)));
- else if (ControlFile->state == DB_SHUTDOWNING)
- elog(LOG, "Data Base System was interrupted while shutting down at %s",
- ctime(&(ControlFile->time)));
- else if (ControlFile->state == DB_IN_RECOVERY)
+ if (readFile >= 0 && (RecPtr->xlogid != readId ||
+ RecPtr->xrecoff / XLogSegSize != readSeg))
{
- elog(LOG, "Data Base System was interrupted being in recovery at %s\n"
- "This propably means that some data blocks are corrupted\n"
- "And you will have to use last backup for recovery",
- ctime(&(ControlFile->time)));
+ close(readFile);
+ readFile = -1;
}
- else if (ControlFile->state == DB_IN_PRODUCTION)
- elog(LOG, "Data Base System was interrupted being in production at %s",
- ctime(&(ControlFile->time)));
-
- LastRec = RecPtr = ControlFile->checkPoint;
- if (!XRecOffIsValid(RecPtr.xrecoff))
- elog(STOP, "Invalid checkPoint in control file");
- elog(LOG, "CheckPoint record at (%u, %u)", RecPtr.xlogid, RecPtr.xrecoff);
-
- record = ReadRecord(&RecPtr, buffer);
- if (record->xl_rmid != RM_XLOG_ID)
- elog(STOP, "Invalid RMID in checkPoint record");
- if (record->xl_len != sizeof(checkPoint))
- elog(STOP, "Invalid length of checkPoint record");
- checkPoint = *((CheckPoint*)((char*)record + SizeOfXLogRecord));
-
- elog(LOG, "Redo record at (%u, %u); Undo record at (%u, %u)",
- checkPoint.redo.xlogid, checkPoint.redo.xrecoff,
- checkPoint.undo.xlogid, checkPoint.undo.xrecoff);
- elog(LOG, "NextTransactionId: %u; NextOid: %u)",
- checkPoint.nextXid, checkPoint.nextOid);
- if (checkPoint.nextXid < FirstTransactionId ||
- checkPoint.nextOid < BootstrapObjectIdData)
- elog(LOG, "Invalid NextTransactionId/NextOid");
-
- ShmemVariableCache->nextXid = checkPoint.nextXid;
- ShmemVariableCache->nextOid = checkPoint.nextOid;
-
- if (XLByteLT(RecPtr, checkPoint.redo))
- elog(STOP, "Invalid redo in checkPoint record");
- if (checkPoint.undo.xrecoff == 0)
- checkPoint.undo = RecPtr;
- if (XLByteLT(RecPtr, checkPoint.undo))
- elog(STOP, "Invalid undo in checkPoint record");
-
- if (XLByteLT(checkPoint.undo, RecPtr) || XLByteLT(checkPoint.redo, RecPtr))
+ readId = RecPtr->xlogid;
+ readSeg = RecPtr->xrecoff / XLogSegSize;
+ if (readFile < 0)
{
- if (ControlFile->state == DB_SHUTDOWNED)
- elog(STOP, "Invalid Redo/Undo record in Shutdowned state");
- recovery = true;
+ noBlck = true;
+ readFile = XLogFileOpen(readId, readSeg, nextmode);
+ if (readFile < 0)
+ goto next_record_is_invalid;
}
- else if (ControlFile->state != DB_SHUTDOWNED)
- recovery = true;
- if (recovery)
- {
- elog(LOG, "The DataBase system was not properly shutdowned\n"
- "Automatic recovery is in progress...");
- ControlFile->state = DB_IN_RECOVERY;
- ControlFile->time = time(NULL);
- UpdateControlFile();
-
- sie_saved = StopIfError;
- StopIfError = true;
-
- /* Is REDO required ? */
- if (XLByteLT(checkPoint.redo, RecPtr))
- record = ReadRecord(&(checkPoint.redo), buffer);
- else /* read past CheckPoint record */
- record = ReadRecord(NULL, buffer);
-
- /* REDO */
- if (record->xl_len != 0)
- {
- elog(LOG, "Redo starts at (%u, %u)",
- ReadRecPtr.xlogid, ReadRecPtr.xrecoff);
- do
- {
- if (record->xl_xid >= ShmemVariableCache->nextXid)
- ShmemVariableCache->nextXid = record->xl_xid + 1;
- RmgrTable[record->xl_rmid].rm_redo(EndRecPtr, record);
- record = ReadRecord(NULL, buffer);
- } while (record->xl_len != 0);
- elog(LOG, "Redo done at (%u, %u)",
- ReadRecPtr.xlogid, ReadRecPtr.xrecoff);
- LastRec = ReadRecPtr;
- }
- else
- elog(LOG, "Redo is not required");
- /* UNDO */
- RecPtr = ReadRecPtr;
- if (XLByteLT(checkPoint.undo, RecPtr))
- {
- elog(LOG, "Undo starts at (%u, %u)",
- RecPtr.xlogid, RecPtr.xrecoff);
- do
- {
- record = ReadRecord(&RecPtr, buffer);
- if (TransactionIdIsValid(record->xl_xid) &&
- !TransactionIdDidCommit(record->xl_xid))
- RmgrTable[record->xl_rmid].rm_undo(record);
- RecPtr = record->xl_prev;
- } while (XLByteLE(checkPoint.undo, RecPtr));
- elog(LOG, "Undo done at (%u, %u)",
- ReadRecPtr.xlogid, ReadRecPtr.xrecoff);
- }
- else
- elog(LOG, "Undo is not required");
- }
-
- /* Init xlog buffer cache */
- record = ReadRecord(&LastRec, buffer);
- logId = EndRecPtr.xlogid;
- logSeg = (EndRecPtr.xrecoff - 1) / XLogSegSize;
- logOff = 0;
- logFile = XLogFileOpen(logId, logSeg, false);
- XLogCtl->xlblocks[0].xlogid = logId;
- XLogCtl->xlblocks[0].xrecoff =
- ((EndRecPtr.xrecoff - 1) / BLCKSZ + 1) * BLCKSZ;
- Insert->currpos = ((char*) Insert->currpage) +
- (EndRecPtr.xrecoff + BLCKSZ - XLogCtl->xlblocks[0].xrecoff);
-
- if (recovery)
- {
- int i;
-
- /*
- * Let resource managers know that recovery is done
- */
- for (i = 0; i <= RM_MAX_ID; i++)
- RmgrTable[record->xl_rmid].rm_redo(ReadRecPtr, NULL);
- CreateCheckPoint(true);
- StopIfError = sie_saved;
- }
-
- ControlFile->state = DB_IN_PRODUCTION;
- ControlFile->time = time(NULL);
- UpdateControlFile();
-
- return;
-}
-
-static XLogRecord*
-ReadRecord(XLogRecPtr *RecPtr, char *buffer)
-{
- XLogRecord *record;
- XLogRecPtr tmpRecPtr = EndRecPtr;
- bool nextmode = (RecPtr == NULL);
- int emode = (nextmode) ? LOG : STOP;
-
- if (nextmode)
- {
- RecPtr = &tmpRecPtr;
- if (nextRecord != NULL)
- {
- record = nextRecord;
- goto got_record;
- }
- if (tmpRecPtr.xrecoff % BLCKSZ != 0)
- tmpRecPtr.xrecoff += (BLCKSZ - tmpRecPtr.xrecoff % BLCKSZ);
- if (tmpRecPtr.xrecoff >= XLogFileSize)
- {
- (tmpRecPtr.xlogid)++;
- tmpRecPtr.xrecoff = 0;
- }
- tmpRecPtr.xrecoff += SizeOfXLogPHD;
- }
- else if (!XRecOffIsValid(RecPtr->xrecoff))
- elog(STOP, "ReadRecord: invalid record offset in (%u, %u)",
- RecPtr->xlogid, RecPtr->xrecoff);
-
- if (readFile >= 0 && (RecPtr->xlogid != readId ||
- RecPtr->xrecoff / XLogSegSize != readSeg))
- {
- close(readFile);
- readFile = -1;
- }
- readId = RecPtr->xlogid;
- readSeg = RecPtr->xrecoff / XLogSegSize;
- if (readFile < 0)
- {
- readOff = (off_t) -1;
- readFile = XLogFileOpen(readId, readSeg, nextmode);
- if (readFile < 0)
- goto next_record_is_invalid;
- }
-
- if (readOff < 0 || readOff != (RecPtr->xrecoff % XLogSegSize) / BLCKSZ)
+ if (noBlck || readOff != (RecPtr->xrecoff % XLogSegSize) / BLCKSZ)
{
readOff = (RecPtr->xrecoff % XLogSegSize) / BLCKSZ;
- if (lseek(readFile, readOff * BLCKSZ, SEEK_SET) < 0)
+ if (lseek(readFile, (off_t)(readOff * BLCKSZ), SEEK_SET) < 0)
elog(STOP, "ReadRecord: lseek(logfile %u seg %u off %u) failed: %d",
readId, readSeg, readOff, errno);
if (read(readFile, readBuf, BLCKSZ) != BLCKSZ)
readId++;
}
close(readFile);
- readOff = (off_t) 0;
+ readOff = 0;
readFile = XLogFileOpen(readId, readSeg, nextmode);
if (readFile < 0)
goto next_record_is_invalid;
elog(LOG, "Formating logfile %u seg %u block %u at offset %u",
readId, readSeg, readOff, EndRecPtr.xrecoff % BLCKSZ);
readFile = XLogFileOpen(readId, readSeg, false);
- if (lseek(readFile, readOff * BLCKSZ, SEEK_SET) < 0)
+ if (lseek(readFile, (off_t)(readOff * BLCKSZ), SEEK_SET) < 0)
elog(STOP, "ReadRecord: lseek(logfile %u seg %u off %u) failed: %d",
readId, readSeg, readOff, errno);
if (read(readFile, readBuf, BLCKSZ) != BLCKSZ)
readId, readSeg, readOff, errno);
memset(readBuf + EndRecPtr.xrecoff % BLCKSZ, 0,
BLCKSZ - EndRecPtr.xrecoff % BLCKSZ);
- if (lseek(readFile, readOff * BLCKSZ, SEEK_SET) < 0)
+ if (lseek(readFile, (off_t)(readOff * BLCKSZ), SEEK_SET) < 0)
elog(STOP, "ReadRecord: lseek(logfile %u seg %u off %u) failed: %d",
readId, readSeg, readOff, errno);
if (write(readFile, readBuf, BLCKSZ) != BLCKSZ)
readId = tmpRecPtr.xlogid;
readSeg = tmpRecPtr.xrecoff / XLogSegSize;
readOff = (tmpRecPtr.xrecoff % XLogSegSize) / BLCKSZ;
+ Assert(readOff > 0);
}
if (readOff > 0)
{
- elog(LOG, "Formating logfile %u seg %u block %u at offset 0",
- readId, readSeg, readOff);
+ if (!XLByteEQ(tmpRecPtr, EndRecPtr))
+ elog(LOG, "Formating logfile %u seg %u block %u at offset 0",
+ readId, readSeg, readOff);
readOff *= BLCKSZ;
memset(readBuf, 0, BLCKSZ);
readFile = XLogFileOpen(readId, readSeg, false);
- if (lseek(readFile, readOff, SEEK_SET) < 0)
+ if (lseek(readFile, (off_t)readOff, SEEK_SET) < 0)
elog(STOP, "ReadRecord: lseek(logfile %u seg %u off %u) failed: %d",
readId, readSeg, readOff, errno);
while (readOff < XLogSegSize)
return(record);
}
+void
+UpdateControlFile()
+{
+ int fd;
+
+tryAgain:
+ fd = open(ControlFilePath, O_RDWR);
+ if (fd < 0 && (errno == EMFILE || errno == ENFILE))
+ {
+ fd = errno;
+ if (!ReleaseDataFile())
+ elog(STOP, "Open(cntlfile) failed: %d (and no one data file can be closed)",
+ fd);
+ goto tryAgain;
+ }
+ if (fd < 0)
+ elog(STOP, "Open(cntlfile) failed: %d", errno);
+
+ if (write(fd, ControlFile, BLCKSZ) != BLCKSZ)
+ elog(STOP, "Write(cntlfile) failed: %d", errno);
+
+ if (fsync(fd) != 0)
+ elog(STOP, "Fsync(cntlfile) failed: %d", errno);
+
+ close(fd);
+
+ return;
+}
+
+int
+XLOGShmemSize()
+{
+ if (XLOGbuffers < MinXLOGbuffers)
+ XLOGbuffers = MinXLOGbuffers;
+
+ return(sizeof(XLogCtlData) + BLCKSZ * XLOGbuffers +
+ sizeof(XLogRecPtr) * XLOGbuffers + BLCKSZ);
+}
+
+void
+XLOGShmemInit(void)
+{
+ bool found;
+
+ if (XLOGbuffers < MinXLOGbuffers)
+ XLOGbuffers = MinXLOGbuffers;
+
+ ControlFile = (ControlFileData*)
+ ShmemInitStruct("Control File", BLCKSZ, &found);
+ Assert(!found);
+ XLogCtl = (XLogCtlData*)
+ ShmemInitStruct("XLOG Ctl", sizeof(XLogCtlData) + BLCKSZ * XLOGbuffers +
+ sizeof(XLogRecPtr) * XLOGbuffers, &found);
+ Assert(!found);
+}
+
+/*
+ * This func must be called ONCE on system install
+ */
+void
+BootStrapXLOG()
+{
+ int fd;
+ char buffer[BLCKSZ];
+ XLogPageHeader page = (XLogPageHeader)buffer;
+ CheckPoint checkPoint;
+ XLogRecord *record;
+
+ fd = open(ControlFilePath, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
+ if (fd < 0)
+ elog(STOP, "BootStrapXLOG failed to create control file (%s): %d",
+ ControlFilePath, errno);
+
+ logFile = XLogFileInit(0, 0);
+
+ checkPoint.redo.xlogid = 0;
+ checkPoint.redo.xrecoff = SizeOfXLogPHD;
+ checkPoint.undo = checkPoint.redo;
+ checkPoint.nextXid = FirstTransactionId;
+ checkPoint.nextOid = BootstrapObjectIdData;
+
+ memset(buffer, 0, BLCKSZ);
+ page->xlp_magic = XLOG_PAGE_MAGIC;
+ page->xlp_info = 0;
+ record = (XLogRecord*) ((char*)page + SizeOfXLogPHD);
+ record->xl_prev.xlogid = 0; record->xl_prev.xrecoff = 0;
+ record->xl_xact_prev = record->xl_prev;
+ record->xl_xid = InvalidTransactionId;
+ record->xl_len = sizeof(checkPoint);
+ record->xl_info = 0;
+ record->xl_rmid = RM_XLOG_ID;
+ memcpy((char*)record + SizeOfXLogRecord, &checkPoint, sizeof(checkPoint));
+
+ if (write(logFile, buffer, BLCKSZ) != BLCKSZ)
+ elog(STOP, "BootStrapXLOG failed to write logfile: %d", errno);
+
+ if (fsync(logFile) != 0)
+ elog(STOP, "BootStrapXLOG failed to fsync logfile: %d", errno);
+
+ close(logFile);
+ logFile = -1;
+
+ memset(buffer, 0, BLCKSZ);
+ ControlFile = (ControlFileData*) buffer;
+ ControlFile->logId = 0;
+ ControlFile->logSeg = 1;
+ ControlFile->checkPoint = checkPoint.redo;
+ ControlFile->time = time(NULL);
+ ControlFile->state = DB_SHUTDOWNED;
+
+ if (write(fd, buffer, BLCKSZ) != BLCKSZ)
+ elog(STOP, "BootStrapXLOG failed to write control file: %d", errno);
+
+ if (fsync(fd) != 0)
+ elog(STOP, "BootStrapXLOG failed to fsync control file: %d", errno);
+
+ close(fd);
+
+ return;
+
+}
+
+static char*
+str_time(time_t tnow)
+{
+ char *result = ctime(&tnow);
+ char *p = strchr(result, '\n');
+
+ if (p != NULL)
+ *p = 0;
+
+ return(result);
+}
+
+/*
+ * This func must be called ONCE on system startup
+ */
+void
+StartupXLOG()
+{
+ XLogCtlInsert *Insert;
+ CheckPoint checkPoint;
+ XLogRecPtr RecPtr,
+ LastRec;
+ XLogRecord *record;
+ char buffer[MAXLOGRECSZ+SizeOfXLogRecord];
+ int fd;
+ int recovery = 0;
+ bool sie_saved = false;
+
+ elog(LOG, "Data Base System is starting up at %s", str_time(time(NULL)));
+
+ XLogCtl->xlblocks = (XLogRecPtr*) (((char *)XLogCtl) + sizeof(XLogCtlData));
+ XLogCtl->pages = ((char *)XLogCtl->xlblocks + sizeof(XLogRecPtr) * XLOGbuffers);
+ XLogCtl->XLogCacheByte = BLCKSZ * XLOGbuffers;
+ XLogCtl->XLogCacheBlck = XLOGbuffers - 1;
+ memset(XLogCtl->xlblocks, 0, sizeof(XLogRecPtr) * XLOGbuffers);
+ XLogCtl->LgwrRqst = LgwrRqst;
+ XLogCtl->LgwrResult = LgwrResult;
+ XLogCtl->Insert.LgwrResult = LgwrResult;
+ XLogCtl->Insert.curridx = 0;
+ XLogCtl->Insert.currpage = (XLogPageHeader) (XLogCtl->pages);
+ XLogCtl->Write.LgwrResult = LgwrResult;
+ XLogCtl->Write.curridx = 0;
+ S_INIT_LOCK(&(XLogCtl->insert_lck));
+ S_INIT_LOCK(&(XLogCtl->info_lck));
+ S_INIT_LOCK(&(XLogCtl->lgwr_lck));
+
+ /*
+ * Open/read Control file
+ */
+tryAgain:
+ fd = open(ControlFilePath, O_RDWR);
+ if (fd < 0 && (errno == EMFILE || errno == ENFILE))
+ {
+ fd = errno;
+ if (!ReleaseDataFile())
+ elog(STOP, "Open(cntlfile) failed: %d (and no one data file can be closed)",
+ fd);
+ goto tryAgain;
+ }
+ if (fd < 0)
+ elog(STOP, "Open(cntlfile) failed: %d", errno);
+
+ if (read(fd, ControlFile, BLCKSZ) != BLCKSZ)
+ elog(STOP, "Read(cntlfile) failed: %d", errno);
+
+ close(fd);
+
+ if (ControlFile->logSeg == 0 ||
+ ControlFile->time <= 0 ||
+ ControlFile->state < DB_SHUTDOWNED ||
+ ControlFile->state > DB_IN_PRODUCTION ||
+ !XRecOffIsValid(ControlFile->checkPoint.xrecoff))
+ elog(STOP, "Control file context is broken");
+
+ if (ControlFile->state == DB_SHUTDOWNED)
+ elog(LOG, "Data Base System was shutdowned at %s",
+ str_time(ControlFile->time));
+ else if (ControlFile->state == DB_SHUTDOWNING)
+ elog(LOG, "Data Base System was interrupted when shutting down at %s",
+ str_time(ControlFile->time));
+ else if (ControlFile->state == DB_IN_RECOVERY)
+ {
+ elog(LOG, "Data Base System was interrupted being in recovery at %s\n"
+ "\tThis propably means that some data blocks are corrupted\n"
+ "\tAnd you will have to use last backup for recovery",
+ str_time(ControlFile->time));
+ }
+ else if (ControlFile->state == DB_IN_PRODUCTION)
+ elog(LOG, "Data Base System was interrupted being in production at %s",
+ str_time(ControlFile->time));
+
+ LastRec = RecPtr = ControlFile->checkPoint;
+ if (!XRecOffIsValid(RecPtr.xrecoff))
+ elog(STOP, "Invalid checkPoint in control file");
+ elog(LOG, "CheckPoint record at (%u, %u)", RecPtr.xlogid, RecPtr.xrecoff);
+
+ record = ReadRecord(&RecPtr, buffer);
+ if (record->xl_rmid != RM_XLOG_ID)
+ elog(STOP, "Invalid RMID in checkPoint record");
+ if (record->xl_len != sizeof(checkPoint))
+ elog(STOP, "Invalid length of checkPoint record");
+ checkPoint = *((CheckPoint*)((char*)record + SizeOfXLogRecord));
+
+ elog(LOG, "Redo record at (%u, %u); Undo record at (%u, %u)",
+ checkPoint.redo.xlogid, checkPoint.redo.xrecoff,
+ checkPoint.undo.xlogid, checkPoint.undo.xrecoff);
+ elog(LOG, "NextTransactionId: %u; NextOid: %u",
+ checkPoint.nextXid, checkPoint.nextOid);
+ if (checkPoint.nextXid < FirstTransactionId ||
+ checkPoint.nextOid < BootstrapObjectIdData)
+#ifdef XLOG
+ elog(STOP, "Invalid NextTransactionId/NextOid");
+#else
+ elog(LOG, "Invalid NextTransactionId/NextOid");
+#endif
+
+#ifdef XLOG
+ ShmemVariableCache->nextXid = checkPoint.nextXid;
+ ShmemVariableCache->nextOid = checkPoint.nextOid;
+#endif
+
+ if (XLByteLT(RecPtr, checkPoint.redo))
+ elog(STOP, "Invalid redo in checkPoint record");
+ if (checkPoint.undo.xrecoff == 0)
+ checkPoint.undo = RecPtr;
+ if (XLByteLT(RecPtr, checkPoint.undo))
+ elog(STOP, "Invalid undo in checkPoint record");
+
+ if (XLByteLT(checkPoint.undo, RecPtr) || XLByteLT(checkPoint.redo, RecPtr))
+ {
+ if (ControlFile->state == DB_SHUTDOWNED)
+ elog(STOP, "Invalid Redo/Undo record in Shutdowned state");
+ recovery = 2;
+ }
+ else if (ControlFile->state != DB_SHUTDOWNED)
+ recovery = 2;
+
+ if (recovery > 0)
+ {
+ elog(LOG, "The DataBase system was not properly shutdowned\n"
+ "\tAutomatic recovery is in progress...");
+ ControlFile->state = DB_IN_RECOVERY;
+ ControlFile->time = time(NULL);
+ UpdateControlFile();
+
+ sie_saved = StopIfError;
+ StopIfError = true;
+
+ /* Is REDO required ? */
+ if (XLByteLT(checkPoint.redo, RecPtr))
+ record = ReadRecord(&(checkPoint.redo), buffer);
+ else /* read past CheckPoint record */
+ record = ReadRecord(NULL, buffer);
+
+ /* REDO */
+ if (record->xl_len != 0)
+ {
+ elog(LOG, "Redo starts at (%u, %u)",
+ ReadRecPtr.xlogid, ReadRecPtr.xrecoff);
+ do
+ {
+#ifdef XLOG
+ if (record->xl_xid >= ShmemVariableCache->nextXid)
+ ShmemVariableCache->nextXid = record->xl_xid + 1;
+#endif
+ RmgrTable[record->xl_rmid].rm_redo(EndRecPtr, record);
+ record = ReadRecord(NULL, buffer);
+ } while (record->xl_len != 0);
+ elog(LOG, "Redo done at (%u, %u)",
+ ReadRecPtr.xlogid, ReadRecPtr.xrecoff);
+ LastRec = ReadRecPtr;
+ }
+ else
+ {
+ elog(LOG, "Redo is not required");
+ recovery--;
+ }
+
+ /* UNDO */
+ RecPtr = ReadRecPtr;
+ if (XLByteLT(checkPoint.undo, RecPtr))
+ {
+ elog(LOG, "Undo starts at (%u, %u)",
+ RecPtr.xlogid, RecPtr.xrecoff);
+ do
+ {
+ record = ReadRecord(&RecPtr, buffer);
+ if (TransactionIdIsValid(record->xl_xid) &&
+ !TransactionIdDidCommit(record->xl_xid))
+ RmgrTable[record->xl_rmid].rm_undo(record);
+ RecPtr = record->xl_prev;
+ } while (XLByteLE(checkPoint.undo, RecPtr));
+ elog(LOG, "Undo done at (%u, %u)",
+ ReadRecPtr.xlogid, ReadRecPtr.xrecoff);
+ }
+ else
+ {
+ elog(LOG, "Undo is not required");
+ recovery--;
+ }
+ }
+
+ /* Init xlog buffer cache */
+ record = ReadRecord(&LastRec, buffer);
+ logId = EndRecPtr.xlogid;
+ logSeg = (EndRecPtr.xrecoff - 1) / XLogSegSize;
+ logOff = 0;
+ logFile = XLogFileOpen(logId, logSeg, false);
+ XLogCtl->xlblocks[0].xlogid = logId;
+ XLogCtl->xlblocks[0].xrecoff =
+ ((EndRecPtr.xrecoff - 1) / BLCKSZ + 1) * BLCKSZ;
+ Insert = &XLogCtl->Insert;
+ memcpy((char*)(Insert->currpage), readBuf, BLCKSZ);
+ Insert->currpos = ((char*) Insert->currpage) +
+ (EndRecPtr.xrecoff + BLCKSZ - XLogCtl->xlblocks[0].xrecoff);
+ Insert->PrevRecord = ControlFile->checkPoint;
+
+ if (recovery > 0)
+ {
+ int i;
+
+ /*
+ * Let resource managers know that recovery is done
+ */
+ for (i = 0; i <= RM_MAX_ID; i++)
+ RmgrTable[record->xl_rmid].rm_redo(ReadRecPtr, NULL);
+ CreateCheckPoint(true);
+ StopIfError = sie_saved;
+ }
+
+ ControlFile->state = DB_IN_PRODUCTION;
+ ControlFile->time = time(NULL);
+ UpdateControlFile();
+
+ elog(LOG, "Data Base System is in production state at %s", str_time(time(NULL)));
+
+ return;
+}
+
+/*
+ * This func must be called ONCE on system shutdown
+ */
+void
+ShutdownXLOG()
+{
+
+ elog(LOG, "Data Base System is shutting down at %s", str_time(time(NULL)));
+
+ CreateCheckPoint(true);
+
+ elog(LOG, "Data Base System is shutdowned at %s", str_time(time(NULL)));
+}
+
void
CreateCheckPoint(bool shutdown)
{
}
/* Get REDO record ptr */
- while (!TAS(&(XLogCtl->insert_lck)))
+ while (TAS(&(XLogCtl->insert_lck)))
{
struct timeval delay = {0, 5000};
FlushBufferPool();
/* Get UNDO record ptr */
+ checkPoint.undo.xrecoff = 0;
if (shutdown && checkPoint.undo.xrecoff != 0)
elog(STOP, "Active transaction while data base is shutting down");
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.68 1999/09/27 20:26:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.69 1999/10/06 21:58:02 vadim Exp $
*
*-------------------------------------------------------------------------
*/
#define ALLOC(t, c) (t *)calloc((unsigned)(c), sizeof(t))
#define FIRST_TYPE_OID 16 /* OID of the first type */
+extern void BaseInit(void);
+extern void StartupXLOG(void);
+extern void ShutdownXLOG(void);
+extern void BootStrapXLOG(void);
+
+extern char XLogDir[];
+extern char ControlFilePath[];
+
extern int Int_yyparse(void);
static hashnode *AddStr(char *str, int strlength, int mderef);
static Form_pg_attribute AllocateAttribute(void);
*/
{
int i;
- int portFd = -1;
char *dbName;
int flag;
- int override = 1; /* use BootstrapProcessing or
- * InitProcessing mode */
+ bool xloginit = false;
extern int optind;
extern char *optarg;
- /* ----------------
- * initialize signal handlers
- * ----------------
- */
- pqsignal(SIGINT, (sig_func) die);
- pqsignal(SIGHUP, (sig_func) die);
- pqsignal(SIGTERM, (sig_func) die);
/* --------------------
* initialize globals
Noversion = false;
dbName = NULL;
DataDir = getenv("PGDATA"); /* Null if no PGDATA variable */
+ IsUnderPostmaster = false;
- while ((flag = getopt(argc, argv, "D:dCOQP:F")) != EOF)
+ while ((flag = getopt(argc, argv, "D:dCQxpB:F")) != EOF)
{
switch (flag)
{
case 'F':
disableFsync = true;
break;
- case 'O':
- override = true;
- break;
case 'Q':
Quiet = true;
break;
- case 'P': /* specify port */
- portFd = atoi(optarg);
+ case 'x':
+ xloginit = true;
+ break;
+ case 'p':
+ IsUnderPostmaster = true;
+ break;
+ case 'B':
+ NBuffers = atoi(optarg);
break;
default:
usage();
else if (argc - optind == 1)
dbName = argv[optind];
+ SetProcessingMode(BootstrapProcessing);
+
if (!DataDir)
{
fprintf(stderr, "%s does not know where to find the database system "
}
}
- /* ----------------
- * initialize input fd
- * ----------------
+ BaseInit();
+
+ if (!IsUnderPostmaster)
+ {
+ pqsignal(SIGINT, (sig_func) die);
+ pqsignal(SIGHUP, (sig_func) die);
+ pqsignal(SIGTERM, (sig_func) die);
+ }
+
+ /*
+ * Bootstrap under Postmaster means two things:
+ * (xloginit) ? StartupXLOG : ShutdownXLOG
+ *
+ * If !under Postmaster and xloginit then BootStrapXLOG.
*/
- if (IsUnderPostmaster && portFd < 0)
+ if (IsUnderPostmaster || xloginit)
{
- fputs("backend: failed, no -P option with -postmaster opt.\n", stderr);
- proc_exit(1);
+ sprintf(XLogDir, "%s%cpg_xlog", DataDir, SEP_CHAR);
+ sprintf(ControlFilePath, "%s%cpg_control", DataDir, SEP_CHAR);
}
- /* ----------------
- * backend initialization
- * ----------------
+ if (IsUnderPostmaster && xloginit)
+ {
+ StartupXLOG();
+ proc_exit(0);
+ }
+
+ if (!IsUnderPostmaster && xloginit)
+ {
+ BootStrapXLOG();
+ }
+
+ /*
+ * backend initialization
*/
- SetProcessingMode((override) ? BootstrapProcessing : InitProcessing);
InitPostgres(dbName);
LockDisable(true);
+ if (IsUnderPostmaster && !xloginit)
+ {
+ ShutdownXLOG();
+ proc_exit(0);
+ }
+
for (i = 0; i < MAXATTR; i++)
{
attrtypes[i] = (Form_pg_attribute) NULL;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.120 1999/09/30 02:45:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.121 1999/10/06 21:58:03 vadim Exp $
*
* NOTES
*
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/proc.h"
+#include "access/xlog.h"
#include "tcop/tcopprot.h"
#include "utils/trace.h"
#include "version.h"
#define INVALID_SOCK (-1)
#define ARGV_SIZE 64
- /*
- * Max time in seconds for socket to linger (close() to block) waiting
- * for frontend to retrieve its message from us.
- */
+#ifdef HAVE_SIGPROCMASK
+sigset_t UnBlockSig,
+ BlockSig;
+#else
+int UnBlockSig,
+ BlockSig;
+#endif
/*
* Info for garbage collection. Whenever a process dies, the Postmaster
static Dllist *PortList;
static unsigned short PostPortName = 0;
-static short ActiveBackends = FALSE;
/*
* This is a boolean indicating that there is at least one backend that
* non-local connections */
#endif
-/*
- * GH: For !HAVE_SIGPROCMASK (NEXTSTEP), TRH implemented an
- * alternative interface.
- */
-#ifdef HAVE_SIGPROCMASK
-static sigset_t oldsigmask,
- newsigmask;
+static pid_t StartupPID = 0,
+ ShutdownPID = 0;
-#else
-static int orgsigmask = sigblock(0);
+#define NoShutdown 0
+#define SmartShutdown 1
+#define FastShutdown 2
-#endif
+static int Shutdown = NoShutdown;
+
+static bool FatalError = false;
/*
* State for assigning random salts and cancel keys.
extern int optind,
opterr;
-
/*
* postmaster.c - function prototypes
*/
-static void pmdaemonize(void);
-static Port *ConnCreate(int serverFd);
-static void ConnFree(Port *port);
-static void reset_shared(unsigned short port);
-static void pmdie(SIGNAL_ARGS);
-static void reaper(SIGNAL_ARGS);
-static void dumpstatus(SIGNAL_ARGS);
-static void CleanupProc(int pid, int exitstatus);
-static int DoBackend(Port *port);
-static void ExitPostmaster(int status);
-static void usage(const char *);
-static int ServerLoop(void);
-static int BackendStartup(Port *port);
-static int readStartupPacket(void *arg, PacketLen len, void *pkt);
-static int processCancelRequest(Port *port, PacketLen len, void *pkt);
-static int initMasks(fd_set *rmask, fd_set *wmask);
-static long PostmasterRandom(void);
-static void RandomSalt(char *salt);
-static void SignalChildren(SIGNAL_ARGS);
-static int CountChildren(void);
+static void pmdaemonize(void);
+static Port *ConnCreate(int serverFd);
+static void ConnFree(Port *port);
+static void reset_shared(unsigned short port);
+static void pmdie(SIGNAL_ARGS);
+static void reaper(SIGNAL_ARGS);
+static void dumpstatus(SIGNAL_ARGS);
+static void CleanupProc(int pid, int exitstatus);
+static int DoBackend(Port *port);
+static void ExitPostmaster(int status);
+static void usage(const char *);
+static int ServerLoop(void);
+static int BackendStartup(Port *port);
+static int readStartupPacket(void *arg, PacketLen len, void *pkt);
+static int processCancelRequest(Port *port, PacketLen len, void *pkt);
+static int initMasks(fd_set *rmask, fd_set *wmask);
+static long PostmasterRandom(void);
+static void RandomSalt(char *salt);
+static void SignalChildren(SIGNAL_ARGS);
+static int CountChildren(void);
+
+extern int BootstrapMain(int argc, char *argv[]);
+static pid_t SSDataBase(bool startup);
+#define StartupDataBase() SSDataBase(true)
+#define ShutdownDataBase() SSDataBase(false)
+
#ifdef USE_SSL
static void InitSSL(void);
#endif
/*
* Set up signal handlers for the postmaster process.
*/
-
- pqsignal(SIGHUP, pmdie); /* send SIGHUP, don't die */
- pqsignal(SIGINT, pmdie); /* die */
- pqsignal(SIGQUIT, pmdie); /* send SIGTERM and die */
- pqsignal(SIGTERM, pmdie); /* send SIGTERM,SIGKILL and die */
- pqsignal(SIGPIPE, SIG_IGN); /* ignored */
- pqsignal(SIGUSR1, pmdie); /* send SIGUSR1 and die */
- pqsignal(SIGUSR2, pmdie); /* send SIGUSR2, don't die */
- pqsignal(SIGCHLD, reaper); /* handle child termination */
- pqsignal(SIGTTIN, SIG_IGN); /* ignored */
- pqsignal(SIGTTOU, SIG_IGN); /* ignored */
- pqsignal(SIGWINCH, dumpstatus); /* dump port status */
+ PG_INITMASK();
+ PG_SETMASK(&BlockSig);
+
+ pqsignal(SIGHUP, pmdie); /* send SIGHUP, don't die */
+ pqsignal(SIGINT, pmdie); /* send SIGTERM and ShutdownDataBase */
+ pqsignal(SIGQUIT, pmdie); /* send SIGUSR1 and die */
+ pqsignal(SIGTERM, pmdie); /* wait for children and ShutdownDataBase */
+ pqsignal(SIGALRM, SIG_IGN); /* ignored */
+ pqsignal(SIGPIPE, SIG_IGN); /* ignored */
+ pqsignal(SIGUSR1, SIG_IGN); /* ignored */
+ pqsignal(SIGUSR2, pmdie); /* send SIGUSR2, don't die */
+ pqsignal(SIGCHLD, reaper); /* handle child termination */
+ pqsignal(SIGTTIN, SIG_IGN); /* ignored */
+ pqsignal(SIGTTOU, SIG_IGN); /* ignored */
+ pqsignal(SIGWINCH, dumpstatus); /* dump port status */
+
+ StartupPID = StartupDataBase();
status = ServerLoop();
nSockets = initMasks(&readmask, &writemask);
-#ifdef HAVE_SIGPROCMASK
- sigprocmask(0, NULL, &oldsigmask);
- sigemptyset(&newsigmask);
- sigaddset(&newsigmask, SIGCHLD);
-#endif
-
for (;;)
{
Port *port;
int no_select = 0;
#endif
-#ifdef HAVE_SIGPROCMASK
- sigprocmask(SIG_SETMASK, &oldsigmask, 0);
-#else
- sigsetmask(orgsigmask);
-#endif
-
memmove((char *) &rmask, (char *) &readmask, sizeof(fd_set));
memmove((char *) &wmask, (char *) &writemask, sizeof(fd_set));
#ifdef USE_SSL
for (curr = DLGetHead(PortList); curr; curr = DLGetSucc(curr))
- if (((Port *)DLE_VAL(curr))->ssl &&
- SSL_pending(((Port *)DLE_VAL(curr))->ssl) > 0) {
- no_select = 1;
- break;
- }
+ {
+ if (((Port *)DLE_VAL(curr))->ssl &&
+ SSL_pending(((Port *)DLE_VAL(curr))->ssl) > 0)
+ {
+ no_select = 1;
+ break;
+ }
+ }
+ PG_SETMASK(&UnBlockSig);
if (no_select)
FD_ZERO(&rmask); /* So we don't accept() anything below */
else
+#else
+ PG_SETMASK(&UnBlockSig);
#endif
if (select(nSockets, &rmask, &wmask, (fd_set *) NULL,
(struct timeval *) NULL) < 0)
}
/*
- * [TRH] To avoid race conditions, block SIGCHLD signals while we
- * are handling the request. (both reaper() and ConnCreate()
- * manipulate the BackEnd list, and reaper() calls free() which is
- * usually non-reentrant.)
+ * Block all signals
*/
-#ifdef HAVE_SIGPROCMASK
- sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
-#else
- sigblock(sigmask(SIGCHLD)); /* XXX[TRH] portability */
-#endif
+ PG_SETMASK(&BlockSig);
/* new connection pending on our well-known port's socket */
}
else
#endif
- if (FD_ISSET(port->sock, &rmask))
- readyread = 1;
+ if (FD_ISSET(port->sock, &rmask))
+ readyread = 1;
if (readyread)
{
if (status == STATUS_OK && port->pktInfo.state == Idle)
{
- /* Can't start backend if max backend count is exceeded. */
- if (CountChildren() >= MaxBackends)
+ /*
+ * Can't start backend if max backend count is exceeded.
+ *
+ * The same when shutdowning data base.
+ */
+ if (Shutdown > NoShutdown)
+ PacketSendError(&port->pktInfo,
+ "The Data Base System is shutting down");
+ else if (StartupPID)
+ PacketSendError(&port->pktInfo,
+ "The Data Base System is starting up");
+ else if (FatalError)
+ PacketSendError(&port->pktInfo,
+ "The Data Base System is in recovery mode");
+ else if (CountChildren() >= MaxBackends)
PacketSendError(&port->pktInfo,
"Sorry, too many clients already");
else
{
-
/*
* If the backend start fails then keep the connection
* open to report it. Otherwise, pretend there is an
{
fprintf(stderr, "%s: ConnCreate: malloc failed\n",
progname);
+ SignalChildren(SIGUSR1);
ExitPostmaster(1);
}
{
ipc_key = port * 1000 + shmem_seq * 100;
CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
- ActiveBackends = FALSE;
shmem_seq += 1;
if (shmem_seq >= 10)
shmem_seq -= 10;
static void
pmdie(SIGNAL_ARGS)
{
- int i;
-
+ PG_SETMASK(&BlockSig);
+
TPRINTF(TRACE_VERBOSE, "pmdie %d", postgres_signal_arg);
- /*
- * Kill self and/or children processes depending on signal number.
- */
switch (postgres_signal_arg)
{
case SIGHUP:
- /* Send SIGHUP to all children (update options flags) */
+ /*
+ * Send SIGHUP to all children (update options flags)
+ */
+ if (Shutdown > SmartShutdown)
+ return;
SignalChildren(SIGHUP);
- /* Don't die */
return;
- case SIGINT:
- /* Die without killing children */
- break;
- case SIGQUIT:
- /* Shutdown all children with SIGTERM */
- SignalChildren(SIGTERM);
- /* Don't die */
+ case SIGUSR2:
+ /*
+ * Send SIGUSR2 to all children (AsyncNotifyHandler)
+ */
+ if (Shutdown > SmartShutdown)
+ return;
+ SignalChildren(SIGUSR2);
return;
+
case SIGTERM:
- /* Shutdown all children with SIGTERM and SIGKILL, then die */
- SignalChildren(SIGTERM);
- for (i = 0; i < 10; i++)
+ /*
+ * Smart Shutdown:
+ *
+ * let children to end their work and ShutdownDataBase.
+ */
+ if (Shutdown >= SmartShutdown)
+ return;
+ Shutdown = SmartShutdown;
+ if (DLGetHead(BackendList)) /* let reaper() handle this */
+ return;
+ /*
+ * No children left. Shutdown data base system.
+ */
+ if (StartupPID > 0 || FatalError) /* let reaper() handle this */
+ return;
+ if (ShutdownPID > 0)
+ abort();
+
+ ShutdownPID = ShutdownDataBase();
+ return;
+
+ case SIGINT:
+ /*
+ * Fast Shutdown:
+ *
+ * abort all children with SIGTERM (rollback active
+ * transactions and exit) and ShutdownDataBase.
+ */
+ if (Shutdown >= FastShutdown)
+ return;
+ if (DLGetHead(BackendList)) /* let reaper() handle this */
{
- if (!DLGetHead(BackendList))
- break;
- sleep(1);
+ if (!FatalError)
+ SignalChildren(SIGTERM);
+ return;
}
- if (DLGetHead(BackendList))
- SignalChildren(SIGKILL);
- break;
- case SIGUSR1:
- /* Quick die all children with SIGUSR1 and die */
- SignalChildren(SIGUSR1);
- break;
- case SIGUSR2:
- /* Send SIGUSR2 to all children (AsyncNotifyHandler) */
- SignalChildren(SIGUSR2);
- /* Don't die */
+ if (Shutdown > NoShutdown)
+ return;
+ Shutdown = FastShutdown;
+ /*
+ * No children left. Shutdown data base system.
+ */
+ if (StartupPID > 0 || FatalError) /* let reaper() handle this */
+ return;
+ if (ShutdownPID > 0)
+ abort();
+
+ ShutdownPID = ShutdownDataBase(); /* flag for reaper() */
return;
+
+ case SIGQUIT:
+ /*
+ * Immediate Shutdown:
+ *
+ * abort all children with SIGUSR1 and exit without
+ * attempt to properly shutdown data base system.
+ */
+ if (ShutdownPID > 0)
+ kill(ShutdownPID, SIGQUIT);
+ else if (StartupPID > 0)
+ kill(StartupPID, SIGQUIT);
+ else if (DLGetHead(BackendList))
+ SignalChildren(SIGUSR1);
+ break;
}
/* exit postmaster */
/* GH: replace waitpid for !HAVE_WAITPID. Does this work ? */
#ifdef HAVE_WAITPID
int status; /* backend exit status */
-
#else
- union wait statusp; /* backend exit status */
-
+ union wait status; /* backend exit status */
#endif
+ int exitstatus;
int pid; /* process id of dead backend */
+ PG_SETMASK(&BlockSig);
+
if (DebugLvl)
fprintf(stderr, "%s: reaping dead processes...\n",
progname);
#ifdef HAVE_WAITPID
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
{
- CleanupProc(pid, status);
- pqsignal(SIGCHLD, reaper);
- }
+ exitstatus = status;
#else
- while ((pid = wait3(&statusp, WNOHANG, NULL)) > 0)
+ while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
{
- CleanupProc(pid, statusp.w_status);
- pqsignal(SIGCHLD, reaper);
- }
+ exitstatus = status.w_status;
#endif
+ if (ShutdownPID > 0)
+ {
+ if (pid != ShutdownPID)
+ abort();
+ if (exitstatus != 0)
+ abort();
+ proc_exit(0);
+ }
+ if (StartupPID > 0)
+ {
+ if (pid != StartupPID)
+ abort();
+ if (exitstatus != 0)
+ abort();
+ StartupPID = 0;
+ FatalError = false;
+ if (Shutdown > NoShutdown)
+ {
+ if (ShutdownPID > 0)
+ abort();
+ ShutdownPID = ShutdownDataBase();
+ }
+ pqsignal(SIGCHLD, reaper);
+ return;
+ }
+ CleanupProc(pid, exitstatus);
+ }
+ pqsignal(SIGCHLD, reaper);
+
+ if (FatalError)
+ {
+ /*
+ * Wait for all children exit then StartupDataBase.
+ */
+ if (DLGetHead(BackendList))
+ return;
+ if (StartupPID > 0 || ShutdownPID > 0)
+ return;
+ if (DebugLvl)
+ fprintf(stderr, "%s: CleanupProc: reinitializing shared memory and semaphores\n",
+ progname);
+ shmem_exit(0);
+ reset_shared(PostPortName);
+ StartupPID = StartupDataBase();
+ return;
+ }
+
+ if (Shutdown > NoShutdown)
+ {
+ if (DLGetHead(BackendList))
+ return;
+ if (StartupPID > 0 || ShutdownPID > 0)
+ return;
+ ShutdownPID = ShutdownDataBase();
+ }
+
}
/*
CleanupProc(int pid,
int exitstatus) /* child's exit status. */
{
- Dlelem *prev,
- *curr;
+ Dlelem *curr,
+ *next;
Backend *bp;
int sig;
return;
}
+ FatalError = true;
curr = DLGetHead(BackendList);
while (curr)
{
+ next = DLGetSucc(curr);
bp = (Backend *) DLE_VAL(curr);
- /* -----------------
+ /*
* SIGUSR1 is the special signal that says exit
* without proc_exit and let the user know what's going on.
* ProcSemaphoreKill() cleans up the backends semaphore. If
* SendStop is set (-s on command line), then we send a SIGSTOP so
* that we can core dumps from all backends by hand.
- * -----------------
*/
sig = (SendStop) ? SIGSTOP : SIGUSR1;
if (bp->pid != pid)
bp->pid);
kill(bp->pid, sig);
}
- ProcRemove(bp->pid);
-
- prev = DLGetPred(curr);
- DLRemove(curr);
- free(bp);
- DLFreeElem(curr);
- if (!prev)
- { /* removed head */
- curr = DLGetHead(BackendList);
- continue;
+ else
+ {
+ /*
+ * I don't like that we call ProcRemove() here, assuming that
+ * shmem may be corrupted! But is there another way to free
+ * backend semaphores? Actually, I believe that we need not
+ * in per backend semaphore at all (we use them to wait on lock
+ * only, couldn't we just sigpause?), so probably we'll
+ * remove this call from here someday. -- vadim 04-10-1999
+ */
+ ProcRemove(pid);
+
+ DLRemove(curr);
+ free(bp);
+ DLFreeElem(curr);
}
- curr = DLGetSucc(prev);
+ curr = next;
}
- /*
- * Nothing up my sleeve here, ActiveBackends means that since the last
- * time we recreated shared memory and sems another frontend has
- * requested and received a connection and I have forked off another
- * backend. This prevents me from reinitializing shared stuff more
- * than once for the set of backends that caused the failure and were
- * killed off.
- */
- if (ActiveBackends == TRUE && Reinit)
- {
- if (DebugLvl)
- fprintf(stderr, "%s: CleanupProc: reinitializing shared memory and semaphores\n",
- progname);
- shmem_exit(0);
- reset_shared(PostPortName);
- }
}
/*
bn->cancel_key = MyCancelKey;
DLAddHead(BackendList, DLNewElem(bn));
- ActiveBackends = TRUE;
-
return STATUS_OK;
}
/* We don't want the postmaster's proc_exit() handlers */
on_exit_reset();
- /* ----------------
- * register signal handlers.
- * Thanks to the postmaster, these are currently blocked.
- * ----------------
+ /*
+ * Signal handlers setting is moved to tcop/postgres...
*/
- pqsignal(SIGINT, die);
-
- pqsignal(SIGHUP, die);
- pqsignal(SIGTERM, die);
- pqsignal(SIGPIPE, die);
- pqsignal(SIGUSR1, quickdie);
- pqsignal(SIGUSR2, Async_NotifyHandler);
- pqsignal(SIGFPE, FloatExceptionHandler);
-
- pqsignal(SIGCHLD, SIG_DFL);
- pqsignal(SIGTTIN, SIG_DFL);
- pqsignal(SIGTTOU, SIG_DFL);
- pqsignal(SIGCONT, SIG_DFL);
-
- /* OK, let's unblock our signals, all together now... */
- sigprocmask(SIG_SETMASK, &oldsigmask, 0);
/* Close the postmaster sockets */
if (NetServer)
/*
* Not sure of the semantics here. When the Postmaster dies, should
* the backends all be killed? probably not.
+ *
+ * MUST -- vadim 05-10-1999
*/
if (ServerSock_INET != INVALID_SOCK)
StreamClose(ServerSock_INET);
static void
dumpstatus(SIGNAL_ARGS)
{
- Dlelem *curr = DLGetHead(PortList);
+ Dlelem *curr;
+ PG_SETMASK(&BlockSig);
+
+ curr = DLGetHead(PortList);
while (curr)
{
Port *port = DLE_VAL(curr);
return cnt;
}
-
#ifdef USE_SSL
/*
* Initialize SSL library and structures
}
}
#endif
+
+static pid_t
+SSDataBase(bool startup)
+{
+ pid_t pid;
+ int i;
+ static char ssEntry[4][2 * ARGV_SIZE];
+
+ for (i = 0; i < 4; ++i)
+ MemSet(ssEntry[i], 0, 2 * ARGV_SIZE);
+
+ sprintf(ssEntry[0], "POSTPORT=%d", PostPortName);
+ putenv(ssEntry[0]);
+ sprintf(ssEntry[1], "POSTID=%d", NextBackendTag);
+ putenv(ssEntry[1]);
+ if (!getenv("PGDATA"))
+ {
+ sprintf(ssEntry[2], "PGDATA=%s", DataDir);
+ putenv(ssEntry[2]);
+ }
+ sprintf(ssEntry[3], "IPC_KEY=%d", ipc_key);
+ putenv(ssEntry[3]);
+
+ fflush(stdout);
+ fflush(stderr);
+
+ if ((pid = fork()) == 0) /* child */
+ {
+ char *av[ARGV_SIZE * 2];
+ int ac = 0;
+ char execbuf[MAXPATHLEN];
+ char nbbuf[ARGV_SIZE];
+ char dbbuf[ARGV_SIZE];
+
+ on_exit_reset();
+ if (NetServer)
+ StreamClose(ServerSock_INET);
+#ifndef __CYGWIN32__
+ StreamClose(ServerSock_UNIX);
+#endif
+
+ StrNCpy(execbuf, Execfile, MAXPATHLEN);
+ av[ac++] = execbuf;
+
+ av[ac++] = "-d";
+
+ sprintf(nbbuf, "-B%u", NBuffers);
+ av[ac++] = nbbuf;
+
+ if (startup)
+ av[ac++] = "-x";
+
+ av[ac++] = "-p";
+
+ StrNCpy(dbbuf, "template1", ARGV_SIZE);
+ av[ac++] = dbbuf;
+
+ av[ac] = (char *) NULL;
+
+ optind = 1;
+
+ pqsignal(SIGQUIT, SIG_DFL);
+#ifdef HAVE_SIGPROCMASK
+ sigdelset(&BlockSig, SIGQUIT);
+#else
+ BlockSig &= ~(sigmask(SIGQUIT));
+#endif
+ PG_SETMASK(&BlockSig);
+
+ BootstrapMain(ac, av);
+ exit(0);
+ }
+
+ /* in parent */
+ if (pid < 0)
+ {
+ fprintf(stderr, "%s Data Base: fork failed: %s\n",
+ ((startup) ? "Startup" : "Shutdown"), strerror(errno));
+ ExitPostmaster(1);
+ }
+
+ NextBackendTag -= 1;
+
+ return(pid);
+}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.30 1999/09/24 00:24:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.31 1999/10/06 21:58:04 vadim Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef HAS_TEST_AND_SET
{
- int status;
extern IpcSemaphoreId WaitIOSemId;
extern IpcSemaphoreId WaitCLSemId;
WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key),
- 1, IPCProtection, 0, 1, &status);
+ 1, IPCProtection, 0, 1);
+ if (WaitIOSemId < 0)
+ elog(FATAL, "InitBufferPool: IpcSemaphoreCreate(WaitIOSemId) failed");
WaitCLSemId = IpcSemaphoreCreate(IPCKeyGetWaitCLSemaphoreKey(key),
1, IPCProtection,
- IpcSemaphoreDefaultStartValue,
- 1, &status);
+ IpcSemaphoreDefaultStartValue, 1);
+ if (WaitCLSemId < 0)
+ elog(FATAL, "InitBufferPool: IpcSemaphoreCreate(WaitCLSemId) failed");
}
#endif
PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.38 1999/07/17 20:17:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.39 1999/10/06 21:58:06 vadim Exp $
*
* NOTES
*
}
}
-
-/****************************************************************************/
-/* IpcSemaphoreCreate(semKey, semNum, permission, semStartValue) */
-/* */
-/* - returns a semaphore identifier: */
-/* */
-/* if key doesn't exist: return a new id, status:= IpcSemIdNotExist */
-/* if key exists: return the old id, status:= IpcSemIdExist */
-/* if semNum > MAX : return # of argument, status:=IpcInvalidArgument */
-/* */
-/****************************************************************************/
-
/*
* Note:
* XXX This should be split into two different calls. One should
int semNum,
int permission,
int semStartValue,
- int removeOnExit,
- int *status)
+ int removeOnExit)
{
int i;
int errStatus;
u_short array[IPC_NMAXSEM];
union semun semun;
- /* get a semaphore if non-existent */
/* check arguments */
if (semNum > IPC_NMAXSEM || semNum <= 0)
- {
- *status = IpcInvalidArgument;
- return 2; /* returns the number of the invalid
- * argument */
- }
+ return(-1);
semId = semget(semKey, 0, 0);
if (semId == -1)
{
- *status = IpcSemIdNotExist; /* there doesn't exist a semaphore */
#ifdef DEBUG_IPC
EPRINTF("calling semget with %d, %d , %d\n",
semKey,
EPRINTF("IpcSemaphoreCreate: semget failed (%s) "
"key=%d, num=%d, permission=%o",
strerror(errno), semKey, semNum, permission);
- proc_exit(3);
+ return(-1);
}
for (i = 0; i < semNum; i++)
array[i] = semStartValue;
{
EPRINTF("IpcSemaphoreCreate: semctl failed (%s) id=%d",
strerror(errno), semId);
+ semctl(semId, 0, IPC_RMID, semun);
+ return(-1);
}
if (removeOnExit)
on_shmem_exit(IPCPrivateSemaphoreKill, (caddr_t) semId);
-
- }
- else
- {
- /* there is a semaphore id for this key */
- *status = IpcSemIdExist;
}
#ifdef DEBUG_IPC
- EPRINTF("\nIpcSemaphoreCreate, status %d, returns %d\n",
- *status,
- semId);
+ EPRINTF("\nIpcSemaphoreCreate, returns %d\n", semId);
fflush(stdout);
fflush(stderr);
#endif
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.30 1999/07/17 20:17:44 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.31 1999/10/06 21:58:06 vadim Exp $
*
*-------------------------------------------------------------------------
*/
CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends)
{
int size;
+ extern int XLOGShmemSize(void);
+ extern void XLOGShmemInit(void);
#ifdef HAS_TEST_AND_SET
- /* ---------------
- * create shared memory for slocks
- * --------------
+ /*
+ * Create shared memory for slocks
*/
CreateAndInitSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
#endif
- /* ----------------
- * kill and create the buffer manager buffer pool (and semaphore)
- * ----------------
+ /*
+ * Kill and create the buffer manager buffer pool (and semaphore)
*/
CreateSpinlocks(IPCKeyGetSpinLockSemaphoreKey(key));
* moderately-accurate estimates for the big hogs, plus 100K for the
* stuff that's too small to bother with estimating.
*/
- size = BufferShmemSize() + LockShmemSize(maxBackends);
+ size = BufferShmemSize() + LockShmemSize(maxBackends) + XLOGShmemSize();
#ifdef STABLE_MEMORY_STORAGE
size += MMShmemSize();
#endif
ShmemCreate(IPCKeyGetBufferMemoryKey(key), size);
ShmemIndexReset();
InitShmem(key, size);
+ XLOGShmemInit();
InitBufferPool(key);
/* ----------------
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.46 1999/09/24 00:24:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.47 1999/10/06 21:58:06 vadim Exp $
*
*-------------------------------------------------------------------------
*/
* bootstrap initialize spin locks so we can start to use the
* allocator and shmem index.
*/
- if (!InitSpinLocks(ShmemBootstrap, IPCKeyGetSpinLockSemaphoreKey(key)))
- return FALSE;
+ InitSpinLocks();
/*
* We have just allocated additional space for two spinlocks. Now
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.20 1999/07/16 04:59:44 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.21 1999/10/06 21:58:06 vadim Exp $
*
*-------------------------------------------------------------------------
*/
#ifdef HAS_TEST_AND_SET
/* real spin lock implementations */
-bool
+void
CreateSpinlocks(IPCKey key)
{
/* the spin lock shared memory must have been created by now */
- return TRUE;
+ return;
}
-bool
-InitSpinLocks(int init, IPCKey key)
+void
+InitSpinLocks(void)
{
extern SPINLOCK ShmemLock;
extern SPINLOCK ShmemIndexLock;
extern SPINLOCK ProcStructLock;
extern SPINLOCK SInvalLock;
extern SPINLOCK OidGenLockId;
-
+ extern SPINLOCK XidGenLockId;
+ extern SPINLOCK ControlFileLockId;
#ifdef STABLE_MEMORY_STORAGE
extern SPINLOCK MMCacheLock;
ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
SInvalLock = (SPINLOCK) SINVALLOCKID;
OidGenLockId = (SPINLOCK) OIDGENLOCKID;
+ XidGenLockId = (SPINLOCK) XIDGENLOCKID;
+ ControlFileLockId = (SPINLOCK) CNTLFILELOCKID;
#ifdef STABLE_MEMORY_STORAGE
MMCacheLock = (SPINLOCK) MMCACHELOCKID;
#endif
- return TRUE;
+ return;
}
#ifdef LOCKDEBUG
* the spinlocks
*
*/
-bool
+void
CreateSpinlocks(IPCKey key)
{
- int status;
- IpcSemaphoreId semid;
-
- semid = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
- IpcSemaphoreDefaultStartValue, 1, &status);
- if (status == IpcSemIdExist)
- {
- IpcSemaphoreKill(key);
- elog(NOTICE, "Destroying old spinlock semaphore");
- semid = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
- IpcSemaphoreDefaultStartValue, 1, &status);
- }
+ SpinLockId = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
+ IpcSemaphoreDefaultStartValue, 1);
- if (semid >= 0)
- {
- SpinLockId = semid;
- return TRUE;
- }
- /* cannot create spinlocks */
- elog(FATAL, "CreateSpinlocks: cannot create spin locks");
- return FALSE;
-}
-
-/*
- * Attach to existing spinlock set
- */
-static bool
-AttachSpinLocks(IPCKey key)
-{
- IpcSemaphoreId id;
+ if (SpinLockId <= 0)
+ elog(STOP, "CreateSpinlocks: cannot create spin locks");
- id = semget(key, MAX_SPINS, 0);
- if (id < 0)
- {
- if (errno == EEXIST)
- {
- /* key is the name of someone else's semaphore */
- elog(FATAL, "AttachSpinlocks: SPIN_KEY belongs to someone else");
- }
- /* cannot create spinlocks */
- elog(FATAL, "AttachSpinlocks: cannot create spin locks");
- return FALSE;
- }
- SpinLockId = id;
- return TRUE;
+ return;
}
/*
* (SJCacheLock) for it. Same story for the main memory storage mgr.
*
*/
-bool
-InitSpinLocks(int init, IPCKey key)
+void
+InitSpinLocks(void)
{
extern SPINLOCK ShmemLock;
extern SPINLOCK ShmemIndexLock;
extern SPINLOCK ProcStructLock;
extern SPINLOCK SInvalLock;
extern SPINLOCK OidGenLockId;
+ extern SPINLOCK XidGenLockId;
+ extern SPINLOCK ControlFileLockId;
#ifdef STABLE_MEMORY_STORAGE
extern SPINLOCK MMCacheLock;
#endif
- if (!init || key != IPC_PRIVATE)
- {
-
- /*
- * if bootstrap and key is IPC_PRIVATE, it means that we are
- * running backend by itself. no need to attach spinlocks
- */
- if (!AttachSpinLocks(key))
- {
- elog(FATAL, "InitSpinLocks: couldnt attach spin locks");
- return FALSE;
- }
- }
-
/* These five (or six) spinlocks have fixed location is shmem */
ShmemLock = (SPINLOCK) SHMEMLOCKID;
ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
SInvalLock = (SPINLOCK) SINVALLOCKID;
OidGenLockId = (SPINLOCK) OIDGENLOCKID;
+ XidGenLockId = (SPINLOCK) XIDGENLOCKID;
+ ControlFileLockId = (SPINLOCK) CNTLFILELOCKID;
#ifdef STABLE_MEMORY_STORAGE
MMCacheLock = (SPINLOCK) MMCACHELOCKID;
#endif
- return TRUE;
+ return;
}
#endif /* HAS_TEST_AND_SET */
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.61 1999/09/24 00:24:41 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.62 1999/10/06 21:58:07 vadim Exp $
*
*-------------------------------------------------------------------------
*/
* This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95
*
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.61 1999/09/24 00:24:41 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.62 1999/10/06 21:58:07 vadim Exp $
*/
#include <sys/time.h>
#include <unistd.h>
#include "storage/proc.h"
#include "utils/trace.h"
-static void HandleDeadLock(int sig);
+void HandleDeadLock(SIGNAL_ARGS);
static void ProcFreeAllSemaphores(void);
#define DeadlockCheckTimer pg_options[OPT_DEADLOCKTIMEOUT]
*/
SPINLOCK ProcStructLock;
-/*
- * For cleanup routines. Don't cleanup if the initialization
- * has not happened.
- */
-static bool ProcInitialized = FALSE;
-
static PROC_HDR *ProcGlobal = NULL;
PROC *MyProc = NULL;
PROC_NSEMS_PER_SET,
IPCProtection,
IpcSemaphoreDefaultStartValue,
- 0,
- &semstat);
+ 0);
+ if (semId < 0)
+ elog(FATAL, "InitProcGlobal: IpcSemaphoreCreate failed");
/* mark this sema set allocated */
ProcGlobal->freeSemMap[i] = (1 << PROC_NSEMS_PER_SET);
}
unsigned long location,
myOffset;
- /* ------------------
- * Routine called if deadlock timer goes off. See ProcSleep()
- * ------------------
- */
- pqsignal(SIGALRM, HandleDeadLock);
-
SpinAcquire(ProcStructLock);
/* attach to the free list */
if (!found)
{
/* this should not happen. InitProcGlobal() is called before this. */
- elog(ERROR, "InitProcess: Proc Header uninitialized");
+ elog(STOP, "InitProcess: Proc Header uninitialized");
}
if (MyProc != NULL)
PROC_NSEMS_PER_SET,
IPCProtection,
IpcSemaphoreDefaultStartValue,
- 0,
- &semstat);
+ 0);
/*
* we might be reusing a semaphore that belongs to a dead backend.
*/
location = MAKE_OFFSET(MyProc);
if ((!ShmemPIDLookup(MyProcPid, &location)) || (location != MAKE_OFFSET(MyProc)))
- elog(FATAL, "InitProc: ShmemPID table broken");
+ elog(STOP, "InitProc: ShmemPID table broken");
MyProc->errType = NO_ERROR;
SHMQueueElemInit(&(MyProc->links));
on_shmem_exit(ProcKill, (caddr_t) MyProcPid);
-
- ProcInitialized = TRUE;
}
/*
* up my semaphore.
* --------------------
*/
-static void
-HandleDeadLock(int sig)
+void
+HandleDeadLock(SIGNAL_ARGS)
{
LOCK *mywaitlock;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.130 1999/09/29 16:06:10 wieck Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.131 1999/10/06 21:58:08 vadim Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
+#include "storage/proc.h"
#include "utils/ps_status.h"
#include "utils/temprel.h"
#include "utils/trace.h"
*/
/*static bool EnableRewrite = true; , never changes why have it*/
-CommandDest whereToSendOutput;
+CommandDest whereToSendOutput = Debug;
/* Define status buffer needed by PS_SET_STATUS */
PS_DEFINE_BUFFER;
+extern void BaseInit(void);
+extern void StartupXLOG(void);
+extern void ShutdownXLOG(void);
+
+extern void HandleDeadLock(SIGNAL_ARGS);
+
+extern char XLogDir[];
+extern char ControlFilePath[];
+
extern int lockingOff;
extern int NBuffers;
/* note: these declarations had better match tcopprot.h */
DLLIMPORT sigjmp_buf Warn_restart;
-bool InError = true;
-
-/*
- * Note: InError is a flag to elog() telling whether it is safe to longjmp
- * back to PostgresMain. It is "false", allowing an error longjmp, during
- * normal processing. It is "true" during startup, when we have not yet
- * set the Warn_restart jmp_buf, and also "true" in the interval when we
- * have executed a longjmp back to PostgresMain and not yet finished cleaning
- * up after the error. In either case, elog(ERROR) should be treated as a
- * fatal exit condition rather than attempting to recover --- since there is
- * noplace to recover to in the first case, and we don't want to risk an
- * infinite loop of "error recoveries" in the second case.
- *
- * Therefore, InError starts out "true" at program load time, as shown above.
- */
+bool InError = false;
+bool ExitAfterAbort = false;
extern int NBuffers;
void
quickdie(SIGNAL_ARGS)
{
+ PG_SETMASK(&BlockSig);
elog(NOTICE, "Message from PostgreSQL backend:"
"\n\tThe Postmaster has informed me that some other backend"
" died abnormally and possibly corrupted shared memory."
* storage. Just nail the windows shut and get out of town.
*/
- exit(0);
+ exit(1);
}
+/*
+ * Abort transaction and exit
+ */
void
die(SIGNAL_ARGS)
{
- ExitPostgres(0);
+ PG_SETMASK(&BlockSig);
+ /*
+ * If ERROR/FATAL is in progress...
+ */
+ if (InError)
+ {
+ ExitAfterAbort = true;
+ return;
+ }
+ elog(FATAL, "The system is shutting down");
}
/* signal handler for floating point exception */
#endif
DataDir = getenv("PGDATA");
+ SetProcessingMode(InitProcessing);
+
/*
* Try to get initial values for date styles and formats. Does not do
* a complete job, but should be good enough for backend. Cannot call
break;
}
- /* ----------------
- * get user name (needed now in case it is the default database name)
- * and check command line validity
- * ----------------
+ if (ShowStats &&
+ (ShowParserStats || ShowPlannerStats || ShowExecutorStats))
+ {
+ fprintf(stderr, "-s can not be used together with -t.\n");
+ proc_exit(1);
+ }
+
+ if (!DataDir)
+ {
+ fprintf(stderr, "%s does not know where to find the database system "
+ "data. You must specify the directory that contains the "
+ "database system either by specifying the -D invocation "
+ "option or by setting the PGDATA environment variable.\n\n",
+ argv[0]);
+ proc_exit(1);
+ }
+
+ /*
+ * 1. Set BlockSig and UnBlockSig masks.
+ * 2. Set up signal handlers.
+ * 3. Allow only SIGUSR1 signal (we never block it)
+ * during initialization.
+ *
+ * Note that postmaster already blocked ALL signals to make us happy.
+ */
+ if (!IsUnderPostmaster)
+ {
+ PG_INITMASK();
+ PG_SETMASK(&BlockSig);
+ }
+
+#ifdef HAVE_SIGPROCMASK
+ sigdelset(&BlockSig, SIGUSR1);
+#else
+ BlockSig &= ~(sigmask(SIGUSR1));
+#endif
+
+ pqsignal(SIGHUP, read_pg_options); /* update pg_options from file */
+ pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
+ pqsignal(SIGQUIT, handle_warn); /* handle error */
+ pqsignal(SIGTERM, die);
+ pqsignal(SIGALRM, HandleDeadLock);
+ /*
+ * Ignore failure to write to frontend. Note: if frontend closes
+ * connection, we will notice it and exit cleanly when control next
+ * returns to outer loop. This seems safer than forcing exit in the
+ * midst of output during who-knows-what operation...
+ */
+ pqsignal(SIGPIPE, SIG_IGN);
+ pqsignal(SIGUSR1, quickdie);
+ pqsignal(SIGUSR2, Async_NotifyHandler); /* flush also sinval cache */
+ pqsignal(SIGFPE, FloatExceptionHandler);
+ pqsignal(SIGCHLD, SIG_IGN); /* ignored, sent by LockOwners */
+ pqsignal(SIGTTIN, SIG_DFL);
+ pqsignal(SIGTTOU, SIG_DFL);
+ pqsignal(SIGCONT, SIG_DFL);
+
+ PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */
+
+ /*
+ * Get user name (needed now in case it is the default database name)
+ * and check command line validity
*/
SetPgUserName();
userName = GetPgUserName();
usage(argv[0]);
proc_exit(1);
}
+ pq_init(); /* initialize libpq at backend startup */
+ whereToSendOutput = Remote;
+ BaseInit();
}
else
{
/* interactive case: database name can be last arg on command line */
+ whereToSendOutput = Debug;
if (errs || argc - optind > 1)
{
usage(argv[0]);
argv[0]);
proc_exit(1);
}
- }
-
- if (ShowStats &&
- (ShowParserStats || ShowPlannerStats || ShowExecutorStats))
- {
- fprintf(stderr, "-s can not be used together with -t.\n");
- proc_exit(1);
- }
-
- if (!DataDir)
- {
- fprintf(stderr, "%s does not know where to find the database system "
- "data. You must specify the directory that contains the "
- "database system either by specifying the -D invocation "
- "option or by setting the PGDATA environment variable.\n\n",
- argv[0]);
- proc_exit(1);
+ BaseInit();
+ sprintf(XLogDir, "%s%cpg_xlog", DataDir, SEP_CHAR);
+ sprintf(ControlFilePath, "%s%cpg_control", DataDir, SEP_CHAR);
+ StartupXLOG();
}
/*
remote_info = remote_host = "unknown";
break;
}
- }
-
- /* ----------------
- * set process params for ps
- * ----------------
- */
- if (IsUnderPostmaster)
- {
+ /*
+ * Set process params for ps
+ */
PS_INIT_STATUS(real_argc, real_argv, argv[0],
remote_info, userName, DBName);
PS_SET_STATUS("startup");
}
+
/* ----------------
* print flags
* ----------------
}
}
- /* ----------------
- * initialize I/O
- * ----------------
- */
- if (IsUnderPostmaster)
- {
- pq_init(); /* initialize libpq at backend startup */
- whereToSendOutput = Remote;
- }
- else
- whereToSendOutput = Debug;
- /* ----------------
- * general initialization
- * ----------------
+ /*
+ * general initialization
*/
- SetProcessingMode(InitProcessing);
if (Verbose)
TPRINTF(TRACE_VERBOSE, "InitPostgres");
parser_input = makeStringInfo(); /* initialize input buffer */
- /* ----------------
- * Set up handler for cancel-request signal, and
- * send this backend's cancellation info to the frontend.
- * This should not be done until we are sure startup is successful.
- * ----------------
- */
-
- pqsignal(SIGHUP, read_pg_options); /* update pg_options from file */
- pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
- pqsignal(SIGQUIT, handle_warn); /* handle error */
- pqsignal(SIGTERM, die);
- pqsignal(SIGPIPE, SIG_IGN); /* ignore failure to write to frontend */
-
- /*
- * Note: if frontend closes connection, we will notice it and exit
- * cleanly when control next returns to outer loop. This seems safer
- * than forcing exit in the midst of output during who-knows-what
- * operation...
+ /*
+ * Send this backend's cancellation info to the frontend.
*/
- pqsignal(SIGUSR1, quickdie);
- pqsignal(SIGUSR2, Async_NotifyHandler); /* flush also sinval cache */
- pqsignal(SIGCHLD, SIG_IGN); /* ignored, sent by LockOwners */
- pqsignal(SIGFPE, FloatExceptionHandler);
-
if (whereToSendOutput == Remote &&
PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
{
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.130 $ $Date: 1999/09/29 16:06:10 $\n");
+ puts("$Revision: 1.131 $ $Date: 1999/10/06 21:58:08 $\n");
}
- /* ----------------
+ /*
* Initialize the deferred trigger manager
- * ----------------
*/
if (DeferredTriggerInit() != 0)
ExitPostgres(1);
- /* ----------------
- * POSTGRES main processing loop begins here
- *
- * if an exception is encountered, processing resumes here
- * so we abort the current transaction and start a new one.
+ /*
+ * POSTGRES main processing loop begins here
*
- * Note: elog(ERROR) does a siglongjmp() to transfer control here.
- * See comments with the declaration of InError, above.
- * ----------------
+ * If an exception is encountered, processing resumes here
+ * so we abort the current transaction and start a new one.
*/
+ SetProcessingMode(NormalProcessing);
+
if (sigsetjmp(Warn_restart, 1) != 0)
{
- InError = true;
-
time(&tim);
if (Verbose)
TPRINTF(TRACE_VERBOSE, "AbortCurrentTransaction");
AbortCurrentTransaction();
+ InError = false;
+ if (ExitAfterAbort)
+ {
+ ProcReleaseLocks(); /* Just to be sure... */
+ ExitPostgres(0);
+ }
}
- InError = false;
+ PG_SETMASK(&UnBlockSig);
/*
* Non-error queries loop here.
*/
case 'X':
case EOF:
+ if (!IsUnderPostmaster)
+ ShutdownXLOG();
pq_close();
proc_exit(0);
break;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.48 1999/09/11 19:06:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.49 1999/10/06 21:58:09 vadim Exp $
*
*-------------------------------------------------------------------------
*/
extern int errno;
extern int sys_nerr;
+extern CommandDest whereToSendOutput;
#ifdef USE_SYSLOG
/*
if (lev <= DEBUG && Debugfile < 0)
return; /* ignore debug msgs if noplace to send */
+ if (lev == ERROR || lev == FATAL)
+ {
+ if (IsInitProcessingMode())
+ {
+ extern TransactionState CurrentTransactionState;
+
+ if (CurrentTransactionState->state != TRANS_DEFAULT &&
+ CurrentTransactionState->state != TRANS_DISABLED)
+ abort();
+ lev = FATAL;
+ }
+ }
+
/* choose message prefix and indent level */
switch (lev)
{
#ifndef PG_STANDALONE
- if (lev > DEBUG && IsUnderPostmaster)
+ if (lev > DEBUG && whereToSendOutput == Remote)
{
/* Send IPC message to the front-end program */
char msgtype;
pq_flush();
}
- if (lev > DEBUG && ! IsUnderPostmaster)
+ if (lev > DEBUG && whereToSendOutput != Remote)
{
/* We are running as an interactive backend, so just send
* the message to stderr.
/*
* Perform error recovery action as specified by lev.
*/
- if (lev == ERROR)
+ if (lev == ERROR || lev == FATAL)
{
if (InError)
{
/* error reported during error recovery; don't loop forever */
elog(REALLYFATAL, "elog: error during error recovery, giving up!");
}
- /* exit to main loop */
+ InError = true;
ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
+ if (lev == FATAL)
+ {
+ if (IsInitProcessingMode())
+ ExitPostgres(0);
+ ExitAfterAbort = true;
+ }
+ /* exit to main loop */
siglongjmp(Warn_restart, 1);
}
- if (lev == FATAL)
- {
- /*
- * Assume that if we have detected the failure we can exit with a
- * normal exit status. This will prevent the postmaster from
- * cleaning up when it's not needed.
- */
- fflush(stdout);
- fflush(stderr);
- ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
- ProcReleaseLocks(); /* get rid of real locks we hold */
- proc_exit(0);
- }
-
if (lev > FATAL)
{
/*
- * Serious crash time. Postmaster will observe nonzero
+ * Serious crash time. Postmaster will observe nonzero
* process exit status and kill the other backends too.
*/
fflush(stdout);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.34 1999/07/17 20:18:08 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.35 1999/10/06 21:58:10 vadim Exp $
*
*-------------------------------------------------------------------------
*/
* processing mode support stuff (used to be in pmod.c)
* ----------------------------------------------------------------
*/
-static ProcessingMode Mode = NoProcessing;
-
-#ifdef NOT_USED
-/*
- * IsNoProcessingMode
- * True iff processing mode is NoProcessing.
- */
-bool
-IsNoProcessingMode()
-{
- return (bool) (Mode == NoProcessing);
-}
-
-#endif
+static ProcessingMode Mode = InitProcessing;
/*
* IsBootstrapProcessingMode
* BadArg if called with invalid mode.
*
* Note:
- * Mode is NoProcessing before the first time this is called.
+ * Mode is InitProcessing before the first time this is called.
*/
void
SetProcessingMode(ProcessingMode mode)
{
- AssertArg(mode == NoProcessing || mode == BootstrapProcessing ||
- mode == InitProcessing || mode == NormalProcessing);
+ AssertArg(mode == BootstrapProcessing || mode == InitProcessing ||
+ mode == NormalProcessing);
Mode = mode;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.50 1999/09/28 11:41:09 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.51 1999/10/06 21:58:10 vadim Exp $
*
* NOTES
* InitPostgres() is the function called from PostgresMain
#include "mb/pg_wchar.h"
#endif
+void BaseInit(void);
+
static void VerifySystemDatabase(void);
static void VerifyMyDatabase(void);
static void ReverifyMyDatabase(char *name);
static void InitCommunication(void);
static void InitMyDatabaseInfo(char *name);
-static void InitStdio(void);
static void InitUserid(void);
{
if (MyBackendTag == -1)
elog(FATAL, "InitCommunication: missing POSTID");
-
- /*
- * Enable this if you are trying to force the backend to run as if
- * it is running under the postmaster.
- *
- * This goto forces Postgres to attach to shared memory instead of
- * using malloc'ed memory (which is the normal behavior if run
- * directly).
- *
- * To enable emulation, run the following shell commands (in addition
- * to enabling this goto)
- *
- * % setenv POSTID 1 % setenv POSTPORT 4321 % setenv IPC_KEY 4321000
- * % postmaster & % kill -9 %1
- *
- * Upon doing this, Postmaster will have allocated the shared memory
- * resources that Postgres will attach to if you enable
- * EMULATE_UNDER_POSTMASTER.
- *
- * This comment may well age with time - it is current as of 8
- * January 1990
- *
- * Greg
- */
-
-#ifdef EMULATE_UNDER_POSTMASTER
-
- goto forcesharedmemory;
-
-#endif
-
}
else if (IsUnderPostmaster)
{
* initialize shared memory and semaphores appropriately.
* ----------------
*/
-#ifdef EMULATE_UNDER_POSTMASTER
-
-forcesharedmemory:
-
-#endif
-
if (!IsUnderPostmaster) /* postmaster already did this */
{
PostgresIpcKey = key;
}
}
-
-/* --------------------------------
- * InitStdio
- *
- * this routine consists of a bunch of code fragments
- * that used to be randomly scattered through cinit().
- * they all seem to do stuff associated with io.
- * --------------------------------
- */
-static void
-InitStdio()
-{
- DebugFileOpen();
-}
-
/* --------------------------------
* InitPostgres
* Initialize POSTGRES.
*/
extern int NBuffers;
-bool PostgresIsInitialized = false;
-
int lockingOff = 0; /* backend -L switch */
/*
{
bool bootstrap; /* true if BootstrapProcessing */
- /* ----------------
- * see if we're running in BootstrapProcessing mode
- * ----------------
+ /*
+ * See if we're running in BootstrapProcessing mode
*/
bootstrap = IsBootstrapProcessingMode();
- /* ----------------
- * turn on the exception handler. Note: we cannot use elog, Assert,
- * AssertState, etc. until after exception handling is on.
- * ----------------
- */
- EnableExceptionHandling(true);
-
- /* ----------------
- * A stupid check to make sure we don't call this more than once.
- * But things like ReinitPostgres() get around this by just diddling
- * the PostgresIsInitialized flag.
- * ----------------
- */
- AssertState(!PostgresIsInitialized);
-
- /* ----------------
- * Memory system initialization.
- * (we may call palloc after EnableMemoryContext())
- *
- * Note EnableMemoryContext() must happen before EnablePortalManager().
- * ----------------
- */
- EnableMemoryContext(true); /* initializes the "top context" */
- EnablePortalManager(true); /* memory for portal/transaction stuff */
-
/* ----------------
* initialize the backend local portal stack used by
* internal PQ function calls. see src/lib/libpq/be-dumpdata.c
*/
be_portalinit();
- /* ----------------
- * attach to shared memory and semaphores, and initialize our
- * input/output/debugging file descriptors.
- * ----------------
- */
- InitCommunication();
- InitStdio();
-
/*
* initialize the local buffer manager
*/
* Will try that, but may not work... - thomas 1997-11-01
*/
- /* Does not touch files (?) - thomas 1997-11-01 */
- smgrinit();
-
- /* ----------------
- * initialize the transaction system and the relation descriptor cache.
- * Note we have to make certain the lock manager is off while we do this.
- * ----------------
+ /*
+ * Initialize the transaction system and the relation descriptor cache.
+ * Note we have to make certain the lock manager is off while we do this.
*/
AmiTransactionOverride(IsBootstrapProcessingMode());
LockDisable(true);
LockDisable(false);
- /* ----------------
+ /*
* Set up my per-backend PROC struct in shared memory.
- * ----------------
*/
InitProcess(PostgresIpcKey);
- /* ----------------
- * Initialize my entry in the shared-invalidation manager's
- * array of per-backend data. (Formerly this came before
- * InitProcess, but now it must happen after, because it uses
- * MyProc.) Once I have done this, I am visible to other backends!
+ /*
+ * Initialize my entry in the shared-invalidation manager's
+ * array of per-backend data. (Formerly this came before
+ * InitProcess, but now it must happen after, because it uses
+ * MyProc.) Once I have done this, I am visible to other backends!
*
- * Sets up MyBackendId, a unique backend identifier.
- * ----------------
+ * Sets up MyBackendId, a unique backend identifier.
*/
InitSharedInvalidationState();
MyBackendId);
}
- /* ----------------
- * initialize the access methods.
- * Does not touch files (?) - thomas 1997-11-01
- * ----------------
+ /*
+ * Initialize the access methods.
+ * Does not touch files (?) - thomas 1997-11-01
*/
initam();
- /* ----------------
- * initialize all the system catalog caches.
- * ----------------
+ /*
+ * Initialize all the system catalog caches.
*/
zerocaches();
*/
InitCatalogCache();
- /* ----------------
- * set ourselves to the proper user id and figure out our postgres
- * user id. If we ever add security so that we check for valid
- * postgres users, we might do it here.
- * ----------------
+ /*
+ * Set ourselves to the proper user id and figure out our postgres
+ * user id. If we ever add security so that we check for valid
+ * postgres users, we might do it here.
*/
InitUserid();
- /* ----------------
- * initialize local data in cache invalidation stuff
- * ----------------
+ /*
+ * Initialize local data in cache invalidation stuff
*/
if (!bootstrap)
InitLocalInvalidateData();
- /* ----------------
- * ok, all done, now let's make sure we don't do it again.
- * ----------------
- */
- PostgresIsInitialized = true;
-
- /* ----------------
- * Done with "InitPostgres", now change to NormalProcessing unless
- * we're in BootstrapProcessing mode.
- * ----------------
- */
- if (!bootstrap)
- SetProcessingMode(NormalProcessing);
if (lockingOff)
LockDisable(true);
if (!bootstrap)
ReverifyMyDatabase(name);
}
+
+void
+BaseInit(void)
+{
+
+ /*
+ * Turn on the exception handler. Note: we cannot use elog, Assert,
+ * AssertState, etc. until after exception handling is on.
+ */
+ EnableExceptionHandling(true);
+
+ /*
+ * Memory system initialization - we may call palloc after
+ * EnableMemoryContext()). Note that EnableMemoryContext()
+ * must happen before EnablePortalManager().
+ */
+ EnableMemoryContext(true); /* initializes the "top context" */
+ EnablePortalManager(true); /* memory for portal/transaction stuff */
+
+ /*
+ * Attach to shared memory and semaphores, and initialize our
+ * input/output/debugging file descriptors.
+ */
+ InitCommunication();
+ DebugFileOpen();
+ smgrinit();
+}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.31 1999/07/15 22:40:15 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.32 1999/10/06 21:58:11 vadim Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/tqual.h"
-extern bool PostgresIsInitialized;
-
SnapshotData SnapshotDirtyData;
Snapshot SnapshotDirty = &SnapshotDirtyData;
if (AMI_OVERRIDE)
return true;
- /*
- * If the transaction system isn't yet initialized, then we assume
- * that transactions committed. We only look at system catalogs
- * during startup, so this is less awful than it seems, but it's still
- * pretty awful.
- */
-
- if (!PostgresIsInitialized)
- return ((bool) (TransactionIdIsValid(tuple->t_xmin) &&
- !TransactionIdIsValid(tuple->t_xmax)));
-
if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
{
if (tuple->t_infomask & HEAP_XMIN_INVALID)
#
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.60 1999/05/20 16:50:06 wieck Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.61 1999/10/06 21:58:12 vadim Exp $
#
#-------------------------------------------------------------------------
mkdir $PGDATA/base
if [ $? -ne 0 ]; then exit 5; fi
fi
+ if [ ! -d $PGDATA/pg_xlog ]; then
+ echo "Creating Postgres database XLOG directory $PGDATA/pg_xlog"
+ echo
+ mkdir $PGDATA/pg_xlog
+ if [ $? -ne 0 ]; then exit 5; fi
+ fi
fi
#----------------------------------------------------------------------------
fi
BACKENDARGS="-boot -C -F -D$PGDATA $BACKEND_TALK_ARG"
+FIRSTRUN="-boot -x -C -F -D$PGDATA $BACKEND_TALK_ARG"
echo "Creating template database in $PGDATA/base/template1"
[ "$debug" -ne 0 ] && echo "Running: postgres $BACKENDARGS template1"
cat $TEMPLATE \
| sed -e "s/postgres PGUID/$POSTGRES_SUPERUSERNAME $POSTGRES_SUPERUID/" \
-e "s/PGUID/$POSTGRES_SUPERUID/" \
-| postgres $BACKENDARGS template1
+| postgres $FIRSTRUN template1
if [ $? -ne 0 ]; then
echo "$CMDNAME: could not create template database"
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: pqsignal.h,v 1.9 1999/02/13 23:21:36 momjian Exp $
+ * $Id: pqsignal.h,v 1.10 1999/10/06 21:58:16 vadim Exp $
*
* NOTES
* This shouldn't be in libpq, but the monitor and some other
#ifndef PQSIGNAL_H
#define PQSIGNAL_H
+#ifdef HAVE_SIGPROCMASK
+extern sigset_t UnBlockSig,
+ BlockSig;
+#define PG_INITMASK() ( \
+ sigemptyset(&UnBlockSig), \
+ sigfillset(&BlockSig) \
+ )
+#define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL)
+#else
+extern int UnBlockSig,
+ BlockSig;
+#define PG_INITMASK() ( \
+ UnBlockSig = 0, \
+ BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) | \
+ sigmask(SIGTERM) | sigmask(SIGALRM) | \
+ sigmask(SIGINT) | sigmask(SIGUSR1) | \
+ sigmask(SIGUSR2) | sigmask(SIGCHLD) | \
+ sigmask(SIGWINCH) | sigmask(SIGFPE) \
+ )
+#define PG_SETMASK(mask) sigsetmask(*((int*)(mask)))
+#endif
+
typedef void (*pqsigfunc) (int);
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: miscadmin.h,v 1.42 1999/09/27 20:27:26 momjian Exp $
+ * $Id: miscadmin.h,v 1.43 1999/10/06 21:58:13 vadim Exp $
*
* NOTES
* some of the information in this file will be moved to
*****************************************************************************/
/*
* Description:
- * There are four processing modes in POSTGRES. They are NoProcessing
- * or "none," BootstrapProcessing or "bootstrap," InitProcessing or
+ * There are three processing modes in POSTGRES. They are
+ * "BootstrapProcessing or "bootstrap," InitProcessing or
* "initialization," and NormalProcessing or "normal."
*
- * If a POSTGRES binary is in normal mode, then all code may be executed
- * normally. In the none mode, only bookkeeping code may be called. In
- * particular, access method calls may not occur in this mode since the
- * execution state is outside a transaction.
- *
- * The final two processing modes are used during special times. When the
+ * The first two processing modes are used during special times. When the
* system state indicates bootstrap processing, transactions are all given
- * transaction id "one" and are consequently guarenteed to commit. This mode
+ * transaction id "one" and are consequently guarenteed to commit. This mode
* is used during the initial generation of template databases.
*
- * Finally, the execution state is in initialization mode until all normal
- * initialization is complete. Some code behaves differently when executed in
- * this mode to enable system bootstrapping.
+ * Initialization mode until all normal initialization is complete.
+ * Some code behaves differently when executed in this mode to enable
+ * system bootstrapping.
+ *
+ * If a POSTGRES binary is in normal mode, then all code may be executed
+ * normally.
*/
typedef enum ProcessingMode
{
- NoProcessing, /* "nothing" can be done */
BootstrapProcessing, /* bootstrap creation of template database */
InitProcessing, /* initializing system */
NormalProcessing /* normal processing */
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: ipc.h,v 1.35 1999/07/15 23:04:10 momjian Exp $
+ * $Id: ipc.h,v 1.36 1999/10/06 21:58:17 vadim Exp $
*
* NOTES
* This file is very architecture-specific. This stuff should actually
extern IpcSemaphoreId IpcSemaphoreCreate(IpcSemaphoreKey semKey,
int semNum, int permission, int semStartValue,
- int removeOnExit, int *status);
+ int removeOnExit);
extern void IpcSemaphoreKill(IpcSemaphoreKey key);
extern void IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock);
extern void IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock);
BUFMGRLOCKID,
LOCKLOCKID,
OIDGENLOCKID,
+ XIDGENLOCKID,
+ CNTLFILELOCKID,
SHMEMLOCKID,
SHMEMINDEXLOCKID,
LOCKMGRLOCKID,
PROCSTRUCTLOCKID,
OIDGENLOCKID,
+ XIDGENLOCKID,
+ CNTLFILELOCKID,
FIRSTFREELOCKID
} _LockId_;
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: spin.h,v 1.9 1999/07/15 23:04:16 momjian Exp $
+ * $Id: spin.h,v 1.10 1999/10/06 21:58:17 vadim Exp $
*
*-------------------------------------------------------------------------
*/
typedef int SPINLOCK;
-extern bool CreateSpinlocks(IPCKey key);
-extern bool InitSpinLocks(int init, IPCKey key);
+extern void CreateSpinlocks(IPCKey key);
+extern void InitSpinLocks(void);
extern void SpinAcquire(SPINLOCK lockid);
extern void SpinRelease(SPINLOCK lockid);
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: tcopprot.h,v 1.21 1999/05/26 12:56:58 momjian Exp $
+ * $Id: tcopprot.h,v 1.22 1999/10/06 21:58:18 vadim Exp $
*
* OLD COMMENTS
* This file was created so that other c files could get the two
#endif
extern DLLIMPORT sigjmp_buf Warn_restart;
extern bool InError;
+extern bool ExitAfterAbort;
#ifndef BOOTSTRAP_INCLUDE
extern List *pg_parse_and_plan(char *query_string, Oid *typev, int nargs,