Commit 47937403 authored by Vadim B. Mikheev's avatar Vadim B. Mikheev

XLOG (also known as WAL -:)) Bootstrap/Startup/Shutdown.

First step in cleaning up backend initialization code.
Fix for FATAL: now FATAL is ERROR + exit.
parent 9dcd8c52
...@@ -14,12 +14,14 @@ ...@@ -14,12 +14,14 @@
void UpdateControlFile(void); void UpdateControlFile(void);
int XLOGShmemSize(void); int XLOGShmemSize(void);
void XLOGShmemInit(void);
void BootStrapXLOG(void); void BootStrapXLOG(void);
void StartupXLOG(void); void StartupXLOG(void);
void ShutdownXLOG(void);
void CreateCheckPoint(bool shutdown); void CreateCheckPoint(bool shutdown);
char *XLogDir = NULL; char XLogDir[MAXPGPATH+1];
char *ControlFilePath = NULL; char ControlFilePath[MAXPGPATH+1];
uint32 XLOGbuffers = 0; uint32 XLOGbuffers = 0;
XLogRecPtr MyLastRecPtr = {0, 0}; XLogRecPtr MyLastRecPtr = {0, 0};
bool StopIfError = false; bool StopIfError = false;
...@@ -81,7 +83,8 @@ static XLogCtlData *XLogCtl = NULL; ...@@ -81,7 +83,8 @@ static XLogCtlData *XLogCtl = NULL;
typedef enum DBState typedef enum DBState
{ {
DB_SHUTDOWNED = 1, DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNING, DB_SHUTDOWNING,
DB_IN_RECOVERY, DB_IN_RECOVERY,
DB_IN_PRODUCTION DB_IN_PRODUCTION
...@@ -114,9 +117,9 @@ typedef struct CheckPoint ...@@ -114,9 +117,9 @@ typedef struct CheckPoint
} CheckPoint; } 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 XLogLastSeg (0xffffffff / XLogSegSize)
#define XLogFileSize (XLogLastSeg * XLogSegSize) #define XLogFileSize (XLogLastSeg * XLogSegSize)
...@@ -166,6 +169,7 @@ static void XLogWrite(char *buffer); ...@@ -166,6 +169,7 @@ static void XLogWrite(char *buffer);
static int XLogFileInit(uint32 log, uint32 seg); static int XLogFileInit(uint32 log, uint32 seg);
static int XLogFileOpen(uint32 log, uint32 seg, bool econt); static int XLogFileOpen(uint32 log, uint32 seg, bool econt);
static XLogRecord *ReadRecord(XLogRecPtr *RecPtr, char *buffer); static XLogRecord *ReadRecord(XLogRecPtr *RecPtr, char *buffer);
static char *str_time(time_t tnow);
static XLgwrResult LgwrResult = {{0, 0}, {0, 0}}; static XLgwrResult LgwrResult = {{0, 0}, {0, 0}};
static XLgwrRqst LgwrRqst = {{0, 0}, {0, 0}}; static XLgwrRqst LgwrRqst = {{0, 0}, {0, 0}};
...@@ -173,14 +177,14 @@ static XLgwrRqst LgwrRqst = {{0, 0}, {0, 0}}; ...@@ -173,14 +177,14 @@ static XLgwrRqst LgwrRqst = {{0, 0}, {0, 0}};
static int logFile = -1; static int logFile = -1;
static uint32 logId = 0; static uint32 logId = 0;
static uint32 logSeg = 0; static uint32 logSeg = 0;
static off_t logOff = 0; static uint32 logOff = 0;
static XLogRecPtr ReadRecPtr; static XLogRecPtr ReadRecPtr;
static XLogRecPtr EndRecPtr; static XLogRecPtr EndRecPtr;
static int readFile = -1; static int readFile = -1;
static uint32 readId = 0; static uint32 readId = 0;
static uint32 readSeg = 0; static uint32 readSeg = 0;
static off_t readOff = (off_t) -1; static uint32 readOff = 0;
static char readBuf[BLCKSZ]; static char readBuf[BLCKSZ];
static XLogRecord *nextRecord = NULL; static XLogRecord *nextRecord = NULL;
...@@ -262,7 +266,13 @@ XLogInsert(RmgrId rmid, char *hdr, uint32 hdrlen, char *buf, uint32 buflen) ...@@ -262,7 +266,13 @@ XLogInsert(RmgrId rmid, char *hdr, uint32 hdrlen, char *buf, uint32 buflen)
freespace -= SizeOfXLogRecord; freespace -= SizeOfXLogRecord;
record = (XLogRecord*) Insert->currpos; record = (XLogRecord*) Insert->currpos;
record->xl_prev = Insert->PrevRecord; record->xl_prev = Insert->PrevRecord;
if (rmid != RM_XLOG_ID)
record->xl_xact_prev = MyLastRecPtr; record->xl_xact_prev = MyLastRecPtr;
else
{
record->xl_xact_prev.xlogid = 0;
record->xl_xact_prev.xrecoff = 0;
}
record->xl_xid = GetCurrentTransactionId(); record->xl_xid = GetCurrentTransactionId();
record->xl_len = (len > freespace) ? freespace : len; record->xl_len = (len > freespace) ? freespace : len;
record->xl_info = (len > freespace) ? XLR_TO_BE_CONTINUED : 0; record->xl_info = (len > freespace) ? XLR_TO_BE_CONTINUED : 0;
...@@ -271,7 +281,7 @@ XLogInsert(RmgrId rmid, char *hdr, uint32 hdrlen, char *buf, uint32 buflen) ...@@ -271,7 +281,7 @@ XLogInsert(RmgrId rmid, char *hdr, uint32 hdrlen, char *buf, uint32 buflen)
RecPtr.xrecoff = RecPtr.xrecoff =
XLogCtl->xlblocks[curridx].xrecoff - BLCKSZ + XLogCtl->xlblocks[curridx].xrecoff - BLCKSZ +
Insert->currpos - ((char*) Insert->currpage); Insert->currpos - ((char*) Insert->currpage);
if (MyLastRecPtr.xrecoff == 0) if (MyLastRecPtr.xrecoff == 0 && rmid != RM_XLOG_ID)
{ {
SpinAcquire(SInvalLock); SpinAcquire(SInvalLock);
MyProc->logRec = RecPtr; MyProc->logRec = RecPtr;
...@@ -489,7 +499,7 @@ XLogFlush(XLogRecPtr record) ...@@ -489,7 +499,7 @@ XLogFlush(XLogRecPtr record)
{ {
logId = LgwrResult.Write.xlogid; logId = LgwrResult.Write.xlogid;
logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize; logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize;
logOff = (off_t) 0; logOff = 0;
logFile = XLogFileOpen(logId, logSeg, false); logFile = XLogFileOpen(logId, logSeg, false);
} }
...@@ -612,7 +622,7 @@ XLogWrite(char *buffer) ...@@ -612,7 +622,7 @@ XLogWrite(char *buffer)
} }
logId = LgwrResult.Write.xlogid; logId = LgwrResult.Write.xlogid;
logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize; logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize;
logOff = (off_t) 0; logOff = 0;
logFile = XLogFileInit(logId, logSeg); logFile = XLogFileInit(logId, logSeg);
SpinAcquire(ControlFileLockId); SpinAcquire(ControlFileLockId);
ControlFile->logId = logId; ControlFile->logId = logId;
...@@ -626,14 +636,14 @@ XLogWrite(char *buffer) ...@@ -626,14 +636,14 @@ XLogWrite(char *buffer)
{ {
logId = LgwrResult.Write.xlogid; logId = LgwrResult.Write.xlogid;
logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize; logSeg = (LgwrResult.Write.xrecoff - 1) / XLogSegSize;
logOff = (off_t) 0; logOff = 0;
logFile = XLogFileOpen(logId, logSeg, false); logFile = XLogFileOpen(logId, logSeg, false);
} }
if (logOff != (LgwrResult.Write.xrecoff - BLCKSZ) % XLogSegSize) if (logOff != (LgwrResult.Write.xrecoff - BLCKSZ) % XLogSegSize)
{ {
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", elog(STOP, "Lseek(logfile %u seg %u off %u) failed: %d",
logId, logSeg, logOff, errno); logId, logSeg, logOff, errno);
} }
...@@ -717,6 +727,10 @@ tryAgain: ...@@ -717,6 +727,10 @@ tryAgain:
elog(STOP, "Fsync(logfile %u seg %u) failed: %d", elog(STOP, "Fsync(logfile %u seg %u) failed: %d",
logId, logSeg, errno); 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);
} }
...@@ -753,376 +767,56 @@ tryAgain: ...@@ -753,376 +767,56 @@ tryAgain:
return(fd); return(fd);
} }
void static XLogRecord*
UpdateControlFile() ReadRecord(XLogRecPtr *RecPtr, char *buffer)
{ {
int fd; XLogRecord *record;
XLogRecPtr tmpRecPtr = EndRecPtr;
bool nextmode = (RecPtr == NULL);
int emode = (nextmode) ? LOG : STOP;
bool noBlck = false;
tryAgain: if (nextmode)
fd = open(ControlFilePath, O_RDWR);
if (fd < 0 && (errno == EMFILE || errno == ENFILE))
{ {
fd = errno; RecPtr = &tmpRecPtr;
if (!ReleaseDataFile()) if (nextRecord != NULL)
elog(STOP, "Open(cntlfile) failed: %d (and no one data file can be closed)", {
fd); record = nextRecord;
goto tryAgain; goto got_record;
} }
if (fd < 0) if (tmpRecPtr.xrecoff % BLCKSZ != 0)
elog(STOP, "Open(cntlfile) failed: %d", errno); tmpRecPtr.xrecoff += (BLCKSZ - tmpRecPtr.xrecoff % BLCKSZ);
if (tmpRecPtr.xrecoff >= XLogFileSize)
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()
{
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: %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))
{ {
fd = errno; (tmpRecPtr.xlogid)++;
if (!ReleaseDataFile()) tmpRecPtr.xrecoff = 0;
elog(STOP, "Open(cntlfile) failed: %d (and no one data file can be closed)",
fd);
goto tryAgain;
} }
if (fd < 0) tmpRecPtr.xrecoff += SizeOfXLogPHD;
elog(STOP, "Open(cntlfile) failed: %d", errno); }
else if (!XRecOffIsValid(RecPtr->xrecoff))
if (read(fd, ControlFile, BLCKSZ) != BLCKSZ) elog(STOP, "ReadRecord: invalid record offset in (%u, %u)",
elog(STOP, "Read(cntlfile) failed: %d", errno); RecPtr->xlogid, RecPtr->xrecoff);
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");
if (ControlFile->state == DB_SHUTDOWNED) if (readFile >= 0 && (RecPtr->xlogid != readId ||
elog(LOG, "Data Base System was properly shutdowned at %s", RecPtr->xrecoff / XLogSegSize != readSeg))
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)
{ {
elog(LOG, "Data Base System was interrupted being in recovery at %s\n" close(readFile);
"This propably means that some data blocks are corrupted\n" readFile = -1;
"And you will have to use last backup for recovery",
ctime(&(ControlFile->time)));
} }
else if (ControlFile->state == DB_IN_PRODUCTION) readId = RecPtr->xlogid;
elog(LOG, "Data Base System was interrupted being in production at %s", readSeg = RecPtr->xrecoff / XLogSegSize;
ctime(&(ControlFile->time))); if (readFile < 0)
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))
{ {
if (ControlFile->state == DB_SHUTDOWNED) noBlck = true;
elog(STOP, "Invalid Redo/Undo record in Shutdowned state"); readFile = XLogFileOpen(readId, readSeg, nextmode);
recovery = true; if (readFile < 0)
goto next_record_is_invalid;
} }
else if (ControlFile->state != DB_SHUTDOWNED)
recovery = true;
if (recovery) if (noBlck || readOff != (RecPtr->xrecoff % XLogSegSize) / BLCKSZ)
{
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)
{ {
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", elog(STOP, "ReadRecord: lseek(logfile %u seg %u off %u) failed: %d",
readId, readSeg, readOff, errno); readId, readSeg, readOff, errno);
if (read(readFile, readBuf, BLCKSZ) != BLCKSZ) if (read(readFile, readBuf, BLCKSZ) != BLCKSZ)
...@@ -1186,7 +880,7 @@ got_record:; ...@@ -1186,7 +880,7 @@ got_record:;
readId++; readId++;
} }
close(readFile); close(readFile);
readOff = (off_t) 0; readOff = 0;
readFile = XLogFileOpen(readId, readSeg, nextmode); readFile = XLogFileOpen(readId, readSeg, nextmode);
if (readFile < 0) if (readFile < 0)
goto next_record_is_invalid; goto next_record_is_invalid;
...@@ -1280,7 +974,7 @@ next_record_is_invalid:; ...@@ -1280,7 +974,7 @@ next_record_is_invalid:;
elog(LOG, "Formating logfile %u seg %u block %u at offset %u", elog(LOG, "Formating logfile %u seg %u block %u at offset %u",
readId, readSeg, readOff, EndRecPtr.xrecoff % BLCKSZ); readId, readSeg, readOff, EndRecPtr.xrecoff % BLCKSZ);
readFile = XLogFileOpen(readId, readSeg, false); 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", elog(STOP, "ReadRecord: lseek(logfile %u seg %u off %u) failed: %d",
readId, readSeg, readOff, errno); readId, readSeg, readOff, errno);
if (read(readFile, readBuf, BLCKSZ) != BLCKSZ) if (read(readFile, readBuf, BLCKSZ) != BLCKSZ)
...@@ -1288,7 +982,7 @@ next_record_is_invalid:; ...@@ -1288,7 +982,7 @@ next_record_is_invalid:;
readId, readSeg, readOff, errno); readId, readSeg, readOff, errno);
memset(readBuf + EndRecPtr.xrecoff % BLCKSZ, 0, memset(readBuf + EndRecPtr.xrecoff % BLCKSZ, 0,
BLCKSZ - EndRecPtr.xrecoff % BLCKSZ); 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", elog(STOP, "ReadRecord: lseek(logfile %u seg %u off %u) failed: %d",
readId, readSeg, readOff, errno); readId, readSeg, readOff, errno);
if (write(readFile, readBuf, BLCKSZ) != BLCKSZ) if (write(readFile, readBuf, BLCKSZ) != BLCKSZ)
...@@ -1303,15 +997,17 @@ next_record_is_invalid:; ...@@ -1303,15 +997,17 @@ next_record_is_invalid:;
readId = tmpRecPtr.xlogid; readId = tmpRecPtr.xlogid;
readSeg = tmpRecPtr.xrecoff / XLogSegSize; readSeg = tmpRecPtr.xrecoff / XLogSegSize;
readOff = (tmpRecPtr.xrecoff % XLogSegSize) / BLCKSZ; readOff = (tmpRecPtr.xrecoff % XLogSegSize) / BLCKSZ;
Assert(readOff > 0);
} }
if (readOff > 0) if (readOff > 0)
{ {
if (!XLByteEQ(tmpRecPtr, EndRecPtr))
elog(LOG, "Formating logfile %u seg %u block %u at offset 0", elog(LOG, "Formating logfile %u seg %u block %u at offset 0",
readId, readSeg, readOff); readId, readSeg, readOff);
readOff *= BLCKSZ; readOff *= BLCKSZ;
memset(readBuf, 0, BLCKSZ); memset(readBuf, 0, BLCKSZ);
readFile = XLogFileOpen(readId, readSeg, false); 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", elog(STOP, "ReadRecord: lseek(logfile %u seg %u off %u) failed: %d",
readId, readSeg, readOff, errno); readId, readSeg, readOff, errno);
while (readOff < XLogSegSize) while (readOff < XLogSegSize)
...@@ -1357,6 +1053,381 @@ next_record_is_invalid:; ...@@ -1357,6 +1053,381 @@ next_record_is_invalid:;
return(record); 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 void
CreateCheckPoint(bool shutdown) CreateCheckPoint(bool shutdown)
{ {
...@@ -1375,7 +1446,7 @@ CreateCheckPoint(bool shutdown) ...@@ -1375,7 +1446,7 @@ CreateCheckPoint(bool shutdown)
} }
/* Get REDO record ptr */ /* Get REDO record ptr */
while (!TAS(&(XLogCtl->insert_lck))) while (TAS(&(XLogCtl->insert_lck)))
{ {
struct timeval delay = {0, 5000}; struct timeval delay = {0, 5000};
...@@ -1410,6 +1481,7 @@ CreateCheckPoint(bool shutdown) ...@@ -1410,6 +1481,7 @@ CreateCheckPoint(bool shutdown)
FlushBufferPool(); FlushBufferPool();
/* Get UNDO record ptr */ /* Get UNDO record ptr */
checkPoint.undo.xrecoff = 0;
if (shutdown && checkPoint.undo.xrecoff != 0) if (shutdown && checkPoint.undo.xrecoff != 0)
elog(STOP, "Active transaction while data base is shutting down"); elog(STOP, "Active transaction while data base is shutting down");
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -39,6 +39,14 @@ ...@@ -39,6 +39,14 @@
#define ALLOC(t, c) (t *)calloc((unsigned)(c), sizeof(t)) #define ALLOC(t, c) (t *)calloc((unsigned)(c), sizeof(t))
#define FIRST_TYPE_OID 16 /* OID of the first type */ #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); extern int Int_yyparse(void);
static hashnode *AddStr(char *str, int strlength, int mderef); static hashnode *AddStr(char *str, int strlength, int mderef);
static Form_pg_attribute AllocateAttribute(void); static Form_pg_attribute AllocateAttribute(void);
...@@ -218,22 +226,13 @@ BootstrapMain(int argc, char *argv[]) ...@@ -218,22 +226,13 @@ BootstrapMain(int argc, char *argv[])
*/ */
{ {
int i; int i;
int portFd = -1;
char *dbName; char *dbName;
int flag; int flag;
int override = 1; /* use BootstrapProcessing or bool xloginit = false;
* InitProcessing mode */
extern int optind; extern int optind;
extern char *optarg; extern char *optarg;
/* ----------------
* initialize signal handlers
* ----------------
*/
pqsignal(SIGINT, (sig_func) die);
pqsignal(SIGHUP, (sig_func) die);
pqsignal(SIGTERM, (sig_func) die);
/* -------------------- /* --------------------
* initialize globals * initialize globals
...@@ -252,8 +251,9 @@ BootstrapMain(int argc, char *argv[]) ...@@ -252,8 +251,9 @@ BootstrapMain(int argc, char *argv[])
Noversion = false; Noversion = false;
dbName = NULL; dbName = NULL;
DataDir = getenv("PGDATA"); /* Null if no PGDATA variable */ 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) switch (flag)
{ {
...@@ -270,14 +270,17 @@ BootstrapMain(int argc, char *argv[]) ...@@ -270,14 +270,17 @@ BootstrapMain(int argc, char *argv[])
case 'F': case 'F':
disableFsync = true; disableFsync = true;
break; break;
case 'O':
override = true;
break;
case 'Q': case 'Q':
Quiet = true; Quiet = true;
break; break;
case 'P': /* specify port */ case 'x':
portFd = atoi(optarg); xloginit = true;
break;
case 'p':
IsUnderPostmaster = true;
break;
case 'B':
NBuffers = atoi(optarg);
break; break;
default: default:
usage(); usage();
...@@ -290,6 +293,8 @@ BootstrapMain(int argc, char *argv[]) ...@@ -290,6 +293,8 @@ BootstrapMain(int argc, char *argv[])
else if (argc - optind == 1) else if (argc - optind == 1)
dbName = argv[optind]; dbName = argv[optind];
SetProcessingMode(BootstrapProcessing);
if (!DataDir) if (!DataDir)
{ {
fprintf(stderr, "%s does not know where to find the database system " fprintf(stderr, "%s does not know where to find the database system "
...@@ -311,24 +316,50 @@ BootstrapMain(int argc, char *argv[]) ...@@ -311,24 +316,50 @@ BootstrapMain(int argc, char *argv[])
} }
} }
/* ---------------- BaseInit();
* initialize input fd
* ---------------- 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); sprintf(XLogDir, "%s%cpg_xlog", DataDir, SEP_CHAR);
proc_exit(1); sprintf(ControlFilePath, "%s%cpg_control", DataDir, SEP_CHAR);
} }
/* ---------------- if (IsUnderPostmaster && xloginit)
{
StartupXLOG();
proc_exit(0);
}
if (!IsUnderPostmaster && xloginit)
{
BootStrapXLOG();
}
/*
* backend initialization * backend initialization
* ----------------
*/ */
SetProcessingMode((override) ? BootstrapProcessing : InitProcessing);
InitPostgres(dbName); InitPostgres(dbName);
LockDisable(true); LockDisable(true);
if (IsUnderPostmaster && !xloginit)
{
ShutdownXLOG();
proc_exit(0);
}
for (i = 0; i < MAXATTR; i++) for (i = 0; i < MAXATTR; i++)
{ {
attrtypes[i] = (Form_pg_attribute) NULL; attrtypes[i] = (Form_pg_attribute) NULL;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* *
...@@ -87,6 +87,7 @@ ...@@ -87,6 +87,7 @@
#include "storage/fd.h" #include "storage/fd.h"
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/proc.h" #include "storage/proc.h"
#include "access/xlog.h"
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "utils/trace.h" #include "utils/trace.h"
#include "version.h" #include "version.h"
...@@ -98,10 +99,13 @@ ...@@ -98,10 +99,13 @@
#define INVALID_SOCK (-1) #define INVALID_SOCK (-1)
#define ARGV_SIZE 64 #define ARGV_SIZE 64
/* #ifdef HAVE_SIGPROCMASK
* Max time in seconds for socket to linger (close() to block) waiting sigset_t UnBlockSig,
* for frontend to retrieve its message from us. BlockSig;
*/ #else
int UnBlockSig,
BlockSig;
#endif
/* /*
* Info for garbage collection. Whenever a process dies, the Postmaster * Info for garbage collection. Whenever a process dies, the Postmaster
...@@ -124,7 +128,6 @@ static Dllist *BackendList; ...@@ -124,7 +128,6 @@ static Dllist *BackendList;
static Dllist *PortList; static Dllist *PortList;
static unsigned short PostPortName = 0; static unsigned short PostPortName = 0;
static short ActiveBackends = FALSE;
/* /*
* This is a boolean indicating that there is at least one backend that * This is a boolean indicating that there is at least one backend that
...@@ -209,18 +212,16 @@ static bool SecureNetServer = false; /* if not zero, postmaster listens for only ...@@ -209,18 +212,16 @@ static bool SecureNetServer = false; /* if not zero, postmaster listens for only
* non-local connections */ * non-local connections */
#endif #endif
/* static pid_t StartupPID = 0,
* GH: For !HAVE_SIGPROCMASK (NEXTSTEP), TRH implemented an ShutdownPID = 0;
* alternative interface.
*/
#ifdef HAVE_SIGPROCMASK
static sigset_t oldsigmask,
newsigmask;
#else #define NoShutdown 0
static int orgsigmask = sigblock(0); #define SmartShutdown 1
#define FastShutdown 2
#endif static int Shutdown = NoShutdown;
static bool FatalError = false;
/* /*
* State for assigning random salts and cancel keys. * State for assigning random salts and cancel keys.
...@@ -234,7 +235,6 @@ extern char *optarg; ...@@ -234,7 +235,6 @@ extern char *optarg;
extern int optind, extern int optind,
opterr; opterr;
/* /*
* postmaster.c - function prototypes * postmaster.c - function prototypes
*/ */
...@@ -258,6 +258,12 @@ static long PostmasterRandom(void); ...@@ -258,6 +258,12 @@ static long PostmasterRandom(void);
static void RandomSalt(char *salt); static void RandomSalt(char *salt);
static void SignalChildren(SIGNAL_ARGS); static void SignalChildren(SIGNAL_ARGS);
static int CountChildren(void); 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 #ifdef USE_SSL
static void InitSSL(void); static void InitSSL(void);
#endif #endif
...@@ -613,19 +619,24 @@ PostmasterMain(int argc, char *argv[]) ...@@ -613,19 +619,24 @@ PostmasterMain(int argc, char *argv[])
/* /*
* Set up signal handlers for the postmaster process. * Set up signal handlers for the postmaster process.
*/ */
PG_INITMASK();
PG_SETMASK(&BlockSig);
pqsignal(SIGHUP, pmdie); /* send SIGHUP, don't die */ pqsignal(SIGHUP, pmdie); /* send SIGHUP, don't die */
pqsignal(SIGINT, pmdie); /* die */ pqsignal(SIGINT, pmdie); /* send SIGTERM and ShutdownDataBase */
pqsignal(SIGQUIT, pmdie); /* send SIGTERM and die */ pqsignal(SIGQUIT, pmdie); /* send SIGUSR1 and die */
pqsignal(SIGTERM, pmdie); /* send SIGTERM,SIGKILL and die */ pqsignal(SIGTERM, pmdie); /* wait for children and ShutdownDataBase */
pqsignal(SIGALRM, SIG_IGN); /* ignored */
pqsignal(SIGPIPE, SIG_IGN); /* ignored */ pqsignal(SIGPIPE, SIG_IGN); /* ignored */
pqsignal(SIGUSR1, pmdie); /* send SIGUSR1 and die */ pqsignal(SIGUSR1, SIG_IGN); /* ignored */
pqsignal(SIGUSR2, pmdie); /* send SIGUSR2, don't die */ pqsignal(SIGUSR2, pmdie); /* send SIGUSR2, don't die */
pqsignal(SIGCHLD, reaper); /* handle child termination */ pqsignal(SIGCHLD, reaper); /* handle child termination */
pqsignal(SIGTTIN, SIG_IGN); /* ignored */ pqsignal(SIGTTIN, SIG_IGN); /* ignored */
pqsignal(SIGTTOU, SIG_IGN); /* ignored */ pqsignal(SIGTTOU, SIG_IGN); /* ignored */
pqsignal(SIGWINCH, dumpstatus); /* dump port status */ pqsignal(SIGWINCH, dumpstatus); /* dump port status */
StartupPID = StartupDataBase();
status = ServerLoop(); status = ServerLoop();
ExitPostmaster(status != STATUS_OK); ExitPostmaster(status != STATUS_OK);
...@@ -702,12 +713,6 @@ ServerLoop(void) ...@@ -702,12 +713,6 @@ ServerLoop(void)
nSockets = initMasks(&readmask, &writemask); nSockets = initMasks(&readmask, &writemask);
#ifdef HAVE_SIGPROCMASK
sigprocmask(0, NULL, &oldsigmask);
sigemptyset(&newsigmask);
sigaddset(&newsigmask, SIGCHLD);
#endif
for (;;) for (;;)
{ {
Port *port; Port *port;
...@@ -717,25 +722,25 @@ ServerLoop(void) ...@@ -717,25 +722,25 @@ ServerLoop(void)
int no_select = 0; int no_select = 0;
#endif #endif
#ifdef HAVE_SIGPROCMASK
sigprocmask(SIG_SETMASK, &oldsigmask, 0);
#else
sigsetmask(orgsigmask);
#endif
memmove((char *) &rmask, (char *) &readmask, sizeof(fd_set)); memmove((char *) &rmask, (char *) &readmask, sizeof(fd_set));
memmove((char *) &wmask, (char *) &writemask, sizeof(fd_set)); memmove((char *) &wmask, (char *) &writemask, sizeof(fd_set));
#ifdef USE_SSL #ifdef USE_SSL
for (curr = DLGetHead(PortList); curr; curr = DLGetSucc(curr)) for (curr = DLGetHead(PortList); curr; curr = DLGetSucc(curr))
{
if (((Port *)DLE_VAL(curr))->ssl && if (((Port *)DLE_VAL(curr))->ssl &&
SSL_pending(((Port *)DLE_VAL(curr))->ssl) > 0) { SSL_pending(((Port *)DLE_VAL(curr))->ssl) > 0)
{
no_select = 1; no_select = 1;
break; break;
} }
}
PG_SETMASK(&UnBlockSig);
if (no_select) if (no_select)
FD_ZERO(&rmask); /* So we don't accept() anything below */ FD_ZERO(&rmask); /* So we don't accept() anything below */
else else
#else
PG_SETMASK(&UnBlockSig);
#endif #endif
if (select(nSockets, &rmask, &wmask, (fd_set *) NULL, if (select(nSockets, &rmask, &wmask, (fd_set *) NULL,
(struct timeval *) NULL) < 0) (struct timeval *) NULL) < 0)
...@@ -765,16 +770,9 @@ ServerLoop(void) ...@@ -765,16 +770,9 @@ ServerLoop(void)
} }
/* /*
* [TRH] To avoid race conditions, block SIGCHLD signals while we * Block all signals
* are handling the request. (both reaper() and ConnCreate()
* manipulate the BackEnd list, and reaper() calls free() which is
* usually non-reentrant.)
*/ */
#ifdef HAVE_SIGPROCMASK PG_SETMASK(&BlockSig);
sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
#else
sigblock(sigmask(SIGCHLD)); /* XXX[TRH] portability */
#endif
/* new connection pending on our well-known port's socket */ /* new connection pending on our well-known port's socket */
...@@ -852,13 +850,25 @@ ServerLoop(void) ...@@ -852,13 +850,25 @@ ServerLoop(void)
if (status == STATUS_OK && port->pktInfo.state == Idle) 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, PacketSendError(&port->pktInfo,
"Sorry, too many clients already"); "Sorry, too many clients already");
else else
{ {
/* /*
* If the backend start fails then keep the connection * If the backend start fails then keep the connection
* open to report it. Otherwise, pretend there is an * open to report it. Otherwise, pretend there is an
...@@ -1113,6 +1123,7 @@ ConnCreate(int serverFd) ...@@ -1113,6 +1123,7 @@ ConnCreate(int serverFd)
{ {
fprintf(stderr, "%s: ConnCreate: malloc failed\n", fprintf(stderr, "%s: ConnCreate: malloc failed\n",
progname); progname);
SignalChildren(SIGUSR1);
ExitPostmaster(1); ExitPostmaster(1);
} }
...@@ -1154,7 +1165,6 @@ reset_shared(unsigned short port) ...@@ -1154,7 +1165,6 @@ reset_shared(unsigned short port)
{ {
ipc_key = port * 1000 + shmem_seq * 100; ipc_key = port * 1000 + shmem_seq * 100;
CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends); CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
ActiveBackends = FALSE;
shmem_seq += 1; shmem_seq += 1;
if (shmem_seq >= 10) if (shmem_seq >= 10)
shmem_seq -= 10; shmem_seq -= 10;
...@@ -1166,49 +1176,94 @@ reset_shared(unsigned short port) ...@@ -1166,49 +1176,94 @@ reset_shared(unsigned short port)
static void static void
pmdie(SIGNAL_ARGS) pmdie(SIGNAL_ARGS)
{ {
int i; PG_SETMASK(&BlockSig);
TPRINTF(TRACE_VERBOSE, "pmdie %d", postgres_signal_arg); TPRINTF(TRACE_VERBOSE, "pmdie %d", postgres_signal_arg);
/*
* Kill self and/or children processes depending on signal number.
*/
switch (postgres_signal_arg) switch (postgres_signal_arg)
{ {
case SIGHUP: case SIGHUP:
/* Send SIGHUP to all children (update options flags) */ /*
* Send SIGHUP to all children (update options flags)
*/
if (Shutdown > SmartShutdown)
return;
SignalChildren(SIGHUP); SignalChildren(SIGHUP);
/* Don't die */
return; return;
case SIGINT: case SIGUSR2:
/* Die without killing children */ /*
break; * Send SIGUSR2 to all children (AsyncNotifyHandler)
case SIGQUIT: */
/* Shutdown all children with SIGTERM */ if (Shutdown > SmartShutdown)
SignalChildren(SIGTERM);
/* Don't die */
return; return;
SignalChildren(SIGUSR2);
return;
case SIGTERM: case SIGTERM:
/* Shutdown all children with SIGTERM and SIGKILL, then die */ /*
SignalChildren(SIGTERM); * Smart Shutdown:
for (i = 0; i < 10; i++) *
* 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)) if (!FatalError)
break; SignalChildren(SIGTERM);
sleep(1); return;
} }
if (DLGetHead(BackendList)) if (Shutdown > NoShutdown)
SignalChildren(SIGKILL); return;
break; Shutdown = FastShutdown;
case SIGUSR1: /*
/* Quick die all children with SIGUSR1 and die */ * 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); SignalChildren(SIGUSR1);
break; break;
case SIGUSR2:
/* Send SIGUSR2 to all children (AsyncNotifyHandler) */
SignalChildren(SIGUSR2);
/* Don't die */
return;
} }
/* exit postmaster */ /* exit postmaster */
...@@ -1224,29 +1279,82 @@ reaper(SIGNAL_ARGS) ...@@ -1224,29 +1279,82 @@ reaper(SIGNAL_ARGS)
/* GH: replace waitpid for !HAVE_WAITPID. Does this work ? */ /* GH: replace waitpid for !HAVE_WAITPID. Does this work ? */
#ifdef HAVE_WAITPID #ifdef HAVE_WAITPID
int status; /* backend exit status */ int status; /* backend exit status */
#else #else
union wait statusp; /* backend exit status */ union wait status; /* backend exit status */
#endif #endif
int exitstatus;
int pid; /* process id of dead backend */ int pid; /* process id of dead backend */
PG_SETMASK(&BlockSig);
if (DebugLvl) if (DebugLvl)
fprintf(stderr, "%s: reaping dead processes...\n", fprintf(stderr, "%s: reaping dead processes...\n",
progname); progname);
#ifdef HAVE_WAITPID #ifdef HAVE_WAITPID
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
{ {
CleanupProc(pid, status); exitstatus = status;
pqsignal(SIGCHLD, reaper);
}
#else #else
while ((pid = wait3(&statusp, WNOHANG, NULL)) > 0) while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
{ {
CleanupProc(pid, statusp.w_status); 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); pqsignal(SIGCHLD, reaper);
return;
} }
#endif 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();
}
} }
/* /*
...@@ -1260,8 +1368,8 @@ static void ...@@ -1260,8 +1368,8 @@ static void
CleanupProc(int pid, CleanupProc(int pid,
int exitstatus) /* child's exit status. */ int exitstatus) /* child's exit status. */
{ {
Dlelem *prev, Dlelem *curr,
*curr; *next;
Backend *bp; Backend *bp;
int sig; int sig;
...@@ -1298,18 +1406,19 @@ CleanupProc(int pid, ...@@ -1298,18 +1406,19 @@ CleanupProc(int pid,
return; return;
} }
FatalError = true;
curr = DLGetHead(BackendList); curr = DLGetHead(BackendList);
while (curr) while (curr)
{ {
next = DLGetSucc(curr);
bp = (Backend *) DLE_VAL(curr); bp = (Backend *) DLE_VAL(curr);
/* ----------------- /*
* SIGUSR1 is the special signal that says exit * SIGUSR1 is the special signal that says exit
* without proc_exit and let the user know what's going on. * without proc_exit and let the user know what's going on.
* ProcSemaphoreKill() cleans up the backends semaphore. If * ProcSemaphoreKill() cleans up the backends semaphore. If
* SendStop is set (-s on command line), then we send a SIGSTOP so * SendStop is set (-s on command line), then we send a SIGSTOP so
* that we can core dumps from all backends by hand. * that we can core dumps from all backends by hand.
* -----------------
*/ */
sig = (SendStop) ? SIGSTOP : SIGUSR1; sig = (SendStop) ? SIGSTOP : SIGUSR1;
if (bp->pid != pid) if (bp->pid != pid)
...@@ -1322,36 +1431,25 @@ CleanupProc(int pid, ...@@ -1322,36 +1431,25 @@ CleanupProc(int pid,
bp->pid); bp->pid);
kill(bp->pid, sig); kill(bp->pid, sig);
} }
ProcRemove(bp->pid); 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);
prev = DLGetPred(curr);
DLRemove(curr); DLRemove(curr);
free(bp); free(bp);
DLFreeElem(curr); DLFreeElem(curr);
if (!prev)
{ /* removed head */
curr = DLGetHead(BackendList);
continue;
} }
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);
}
} }
/* /*
...@@ -1516,8 +1614,6 @@ BackendStartup(Port *port) ...@@ -1516,8 +1614,6 @@ BackendStartup(Port *port)
bn->cancel_key = MyCancelKey; bn->cancel_key = MyCancelKey;
DLAddHead(BackendList, DLNewElem(bn)); DLAddHead(BackendList, DLNewElem(bn));
ActiveBackends = TRUE;
return STATUS_OK; return STATUS_OK;
} }
...@@ -1586,27 +1682,9 @@ DoBackend(Port *port) ...@@ -1586,27 +1682,9 @@ DoBackend(Port *port)
/* We don't want the postmaster's proc_exit() handlers */ /* We don't want the postmaster's proc_exit() handlers */
on_exit_reset(); on_exit_reset();
/* ---------------- /*
* register signal handlers. * Signal handlers setting is moved to tcop/postgres...
* Thanks to the postmaster, these are currently blocked.
* ----------------
*/ */
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 */ /* Close the postmaster sockets */
if (NetServer) if (NetServer)
...@@ -1739,6 +1817,8 @@ ExitPostmaster(int status) ...@@ -1739,6 +1817,8 @@ ExitPostmaster(int status)
/* /*
* Not sure of the semantics here. When the Postmaster dies, should * Not sure of the semantics here. When the Postmaster dies, should
* the backends all be killed? probably not. * the backends all be killed? probably not.
*
* MUST -- vadim 05-10-1999
*/ */
if (ServerSock_INET != INVALID_SOCK) if (ServerSock_INET != INVALID_SOCK)
StreamClose(ServerSock_INET); StreamClose(ServerSock_INET);
...@@ -1752,8 +1832,11 @@ ExitPostmaster(int status) ...@@ -1752,8 +1832,11 @@ ExitPostmaster(int status)
static void static void
dumpstatus(SIGNAL_ARGS) dumpstatus(SIGNAL_ARGS)
{ {
Dlelem *curr = DLGetHead(PortList); Dlelem *curr;
PG_SETMASK(&BlockSig);
curr = DLGetHead(PortList);
while (curr) while (curr)
{ {
Port *port = DLE_VAL(curr); Port *port = DLE_VAL(curr);
...@@ -1837,7 +1920,6 @@ CountChildren(void) ...@@ -1837,7 +1920,6 @@ CountChildren(void)
return cnt; return cnt;
} }
#ifdef USE_SSL #ifdef USE_SSL
/* /*
* Initialize SSL library and structures * Initialize SSL library and structures
...@@ -1868,3 +1950,88 @@ static void InitSSL(void) { ...@@ -1868,3 +1950,88 @@ static void InitSSL(void) {
} }
} }
#endif #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);
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -230,16 +230,18 @@ InitBufferPool(IPCKey key) ...@@ -230,16 +230,18 @@ InitBufferPool(IPCKey key)
#ifndef HAS_TEST_AND_SET #ifndef HAS_TEST_AND_SET
{ {
int status;
extern IpcSemaphoreId WaitIOSemId; extern IpcSemaphoreId WaitIOSemId;
extern IpcSemaphoreId WaitCLSemId; extern IpcSemaphoreId WaitCLSemId;
WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key), 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), WaitCLSemId = IpcSemaphoreCreate(IPCKeyGetWaitCLSemaphoreKey(key),
1, IPCProtection, 1, IPCProtection,
IpcSemaphoreDefaultStartValue, IpcSemaphoreDefaultStartValue, 1);
1, &status); if (WaitCLSemId < 0)
elog(FATAL, "InitBufferPool: IpcSemaphoreCreate(WaitCLSemId) failed");
} }
#endif #endif
PrivateRefCount = (long *) calloc(NBuffers, sizeof(long)); PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* *
...@@ -284,18 +284,6 @@ IPCPrivateMemoryKill(int status, ...@@ -284,18 +284,6 @@ IPCPrivateMemoryKill(int status,
} }
} }
/****************************************************************************/
/* 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: * Note:
* XXX This should be split into two different calls. One should * XXX This should be split into two different calls. One should
...@@ -312,8 +300,7 @@ IpcSemaphoreCreate(IpcSemaphoreKey semKey, ...@@ -312,8 +300,7 @@ IpcSemaphoreCreate(IpcSemaphoreKey semKey,
int semNum, int semNum,
int permission, int permission,
int semStartValue, int semStartValue,
int removeOnExit, int removeOnExit)
int *status)
{ {
int i; int i;
int errStatus; int errStatus;
...@@ -321,20 +308,14 @@ IpcSemaphoreCreate(IpcSemaphoreKey semKey, ...@@ -321,20 +308,14 @@ IpcSemaphoreCreate(IpcSemaphoreKey semKey,
u_short array[IPC_NMAXSEM]; u_short array[IPC_NMAXSEM];
union semun semun; union semun semun;
/* get a semaphore if non-existent */
/* check arguments */ /* check arguments */
if (semNum > IPC_NMAXSEM || semNum <= 0) if (semNum > IPC_NMAXSEM || semNum <= 0)
{ return(-1);
*status = IpcInvalidArgument;
return 2; /* returns the number of the invalid
* argument */
}
semId = semget(semKey, 0, 0); semId = semget(semKey, 0, 0);
if (semId == -1) if (semId == -1)
{ {
*status = IpcSemIdNotExist; /* there doesn't exist a semaphore */
#ifdef DEBUG_IPC #ifdef DEBUG_IPC
EPRINTF("calling semget with %d, %d , %d\n", EPRINTF("calling semget with %d, %d , %d\n",
semKey, semKey,
...@@ -348,7 +329,7 @@ IpcSemaphoreCreate(IpcSemaphoreKey semKey, ...@@ -348,7 +329,7 @@ IpcSemaphoreCreate(IpcSemaphoreKey semKey,
EPRINTF("IpcSemaphoreCreate: semget failed (%s) " EPRINTF("IpcSemaphoreCreate: semget failed (%s) "
"key=%d, num=%d, permission=%o", "key=%d, num=%d, permission=%o",
strerror(errno), semKey, semNum, permission); strerror(errno), semKey, semNum, permission);
proc_exit(3); return(-1);
} }
for (i = 0; i < semNum; i++) for (i = 0; i < semNum; i++)
array[i] = semStartValue; array[i] = semStartValue;
...@@ -358,22 +339,16 @@ IpcSemaphoreCreate(IpcSemaphoreKey semKey, ...@@ -358,22 +339,16 @@ IpcSemaphoreCreate(IpcSemaphoreKey semKey,
{ {
EPRINTF("IpcSemaphoreCreate: semctl failed (%s) id=%d", EPRINTF("IpcSemaphoreCreate: semctl failed (%s) id=%d",
strerror(errno), semId); strerror(errno), semId);
semctl(semId, 0, IPC_RMID, semun);
return(-1);
} }
if (removeOnExit) if (removeOnExit)
on_shmem_exit(IPCPrivateSemaphoreKill, (caddr_t) semId); on_shmem_exit(IPCPrivateSemaphoreKill, (caddr_t) semId);
}
else
{
/* there is a semaphore id for this key */
*status = IpcSemIdExist;
} }
#ifdef DEBUG_IPC #ifdef DEBUG_IPC
EPRINTF("\nIpcSemaphoreCreate, status %d, returns %d\n", EPRINTF("\nIpcSemaphoreCreate, returns %d\n", semId);
*status,
semId);
fflush(stdout); fflush(stdout);
fflush(stderr); fflush(stderr);
#endif #endif
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -54,17 +54,17 @@ void ...@@ -54,17 +54,17 @@ void
CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends) CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends)
{ {
int size; int size;
extern int XLOGShmemSize(void);
extern void XLOGShmemInit(void);
#ifdef HAS_TEST_AND_SET #ifdef HAS_TEST_AND_SET
/* --------------- /*
* create shared memory for slocks * Create shared memory for slocks
* --------------
*/ */
CreateAndInitSLockMemory(IPCKeyGetSLockSharedMemoryKey(key)); CreateAndInitSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
#endif #endif
/* ---------------- /*
* kill and create the buffer manager buffer pool (and semaphore) * Kill and create the buffer manager buffer pool (and semaphore)
* ----------------
*/ */
CreateSpinlocks(IPCKeyGetSpinLockSemaphoreKey(key)); CreateSpinlocks(IPCKeyGetSpinLockSemaphoreKey(key));
...@@ -73,7 +73,7 @@ CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends) ...@@ -73,7 +73,7 @@ CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends)
* moderately-accurate estimates for the big hogs, plus 100K for the * moderately-accurate estimates for the big hogs, plus 100K for the
* stuff that's too small to bother with estimating. * stuff that's too small to bother with estimating.
*/ */
size = BufferShmemSize() + LockShmemSize(maxBackends); size = BufferShmemSize() + LockShmemSize(maxBackends) + XLOGShmemSize();
#ifdef STABLE_MEMORY_STORAGE #ifdef STABLE_MEMORY_STORAGE
size += MMShmemSize(); size += MMShmemSize();
#endif #endif
...@@ -89,6 +89,7 @@ CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends) ...@@ -89,6 +89,7 @@ CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends)
ShmemCreate(IPCKeyGetBufferMemoryKey(key), size); ShmemCreate(IPCKeyGetBufferMemoryKey(key), size);
ShmemIndexReset(); ShmemIndexReset();
InitShmem(key, size); InitShmem(key, size);
XLOGShmemInit();
InitBufferPool(key); InitBufferPool(key);
/* ---------------- /* ----------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -187,8 +187,7 @@ InitShmem(unsigned int key, unsigned int size) ...@@ -187,8 +187,7 @@ InitShmem(unsigned int key, unsigned int size)
* bootstrap initialize spin locks so we can start to use the * bootstrap initialize spin locks so we can start to use the
* allocator and shmem index. * allocator and shmem index.
*/ */
if (!InitSpinLocks(ShmemBootstrap, IPCKeyGetSpinLockSemaphoreKey(key))) InitSpinLocks();
return FALSE;
/* /*
* We have just allocated additional space for two spinlocks. Now * We have just allocated additional space for two spinlocks. Now
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -40,15 +40,15 @@ IpcSemaphoreId SpinLockId; ...@@ -40,15 +40,15 @@ IpcSemaphoreId SpinLockId;
#ifdef HAS_TEST_AND_SET #ifdef HAS_TEST_AND_SET
/* real spin lock implementations */ /* real spin lock implementations */
bool void
CreateSpinlocks(IPCKey key) CreateSpinlocks(IPCKey key)
{ {
/* the spin lock shared memory must have been created by now */ /* the spin lock shared memory must have been created by now */
return TRUE; return;
} }
bool void
InitSpinLocks(int init, IPCKey key) InitSpinLocks(void)
{ {
extern SPINLOCK ShmemLock; extern SPINLOCK ShmemLock;
extern SPINLOCK ShmemIndexLock; extern SPINLOCK ShmemIndexLock;
...@@ -57,7 +57,8 @@ InitSpinLocks(int init, IPCKey key) ...@@ -57,7 +57,8 @@ InitSpinLocks(int init, IPCKey key)
extern SPINLOCK ProcStructLock; extern SPINLOCK ProcStructLock;
extern SPINLOCK SInvalLock; extern SPINLOCK SInvalLock;
extern SPINLOCK OidGenLockId; extern SPINLOCK OidGenLockId;
extern SPINLOCK XidGenLockId;
extern SPINLOCK ControlFileLockId;
#ifdef STABLE_MEMORY_STORAGE #ifdef STABLE_MEMORY_STORAGE
extern SPINLOCK MMCacheLock; extern SPINLOCK MMCacheLock;
...@@ -71,12 +72,14 @@ InitSpinLocks(int init, IPCKey key) ...@@ -71,12 +72,14 @@ InitSpinLocks(int init, IPCKey key)
ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID; ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
SInvalLock = (SPINLOCK) SINVALLOCKID; SInvalLock = (SPINLOCK) SINVALLOCKID;
OidGenLockId = (SPINLOCK) OIDGENLOCKID; OidGenLockId = (SPINLOCK) OIDGENLOCKID;
XidGenLockId = (SPINLOCK) XIDGENLOCKID;
ControlFileLockId = (SPINLOCK) CNTLFILELOCKID;
#ifdef STABLE_MEMORY_STORAGE #ifdef STABLE_MEMORY_STORAGE
MMCacheLock = (SPINLOCK) MMCACHELOCKID; MMCacheLock = (SPINLOCK) MMCACHELOCKID;
#endif #endif
return TRUE; return;
} }
#ifdef LOCKDEBUG #ifdef LOCKDEBUG
...@@ -224,55 +227,17 @@ SpinIsLocked(SPINLOCK lock) ...@@ -224,55 +227,17 @@ SpinIsLocked(SPINLOCK lock)
* the spinlocks * the spinlocks
* *
*/ */
bool void
CreateSpinlocks(IPCKey key) CreateSpinlocks(IPCKey key)
{ {
int status; SpinLockId = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
IpcSemaphoreId semid; IpcSemaphoreDefaultStartValue, 1);
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);
}
if (semid >= 0)
{
SpinLockId = semid;
return TRUE;
}
/* cannot create spinlocks */
elog(FATAL, "CreateSpinlocks: cannot create spin locks");
return FALSE;
}
/* if (SpinLockId <= 0)
* Attach to existing spinlock set elog(STOP, "CreateSpinlocks: cannot create spin locks");
*/
static bool
AttachSpinLocks(IPCKey key)
{
IpcSemaphoreId id;
id = semget(key, MAX_SPINS, 0); return;
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;
} }
/* /*
...@@ -287,8 +252,8 @@ AttachSpinLocks(IPCKey key) ...@@ -287,8 +252,8 @@ AttachSpinLocks(IPCKey key)
* (SJCacheLock) for it. Same story for the main memory storage mgr. * (SJCacheLock) for it. Same story for the main memory storage mgr.
* *
*/ */
bool void
InitSpinLocks(int init, IPCKey key) InitSpinLocks(void)
{ {
extern SPINLOCK ShmemLock; extern SPINLOCK ShmemLock;
extern SPINLOCK ShmemIndexLock; extern SPINLOCK ShmemIndexLock;
...@@ -297,26 +262,14 @@ InitSpinLocks(int init, IPCKey key) ...@@ -297,26 +262,14 @@ InitSpinLocks(int init, IPCKey key)
extern SPINLOCK ProcStructLock; extern SPINLOCK ProcStructLock;
extern SPINLOCK SInvalLock; extern SPINLOCK SInvalLock;
extern SPINLOCK OidGenLockId; extern SPINLOCK OidGenLockId;
extern SPINLOCK XidGenLockId;
extern SPINLOCK ControlFileLockId;
#ifdef STABLE_MEMORY_STORAGE #ifdef STABLE_MEMORY_STORAGE
extern SPINLOCK MMCacheLock; extern SPINLOCK MMCacheLock;
#endif #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 */ /* These five (or six) spinlocks have fixed location is shmem */
ShmemLock = (SPINLOCK) SHMEMLOCKID; ShmemLock = (SPINLOCK) SHMEMLOCKID;
ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID; ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
...@@ -325,12 +278,14 @@ InitSpinLocks(int init, IPCKey key) ...@@ -325,12 +278,14 @@ InitSpinLocks(int init, IPCKey key)
ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID; ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
SInvalLock = (SPINLOCK) SINVALLOCKID; SInvalLock = (SPINLOCK) SINVALLOCKID;
OidGenLockId = (SPINLOCK) OIDGENLOCKID; OidGenLockId = (SPINLOCK) OIDGENLOCKID;
XidGenLockId = (SPINLOCK) XIDGENLOCKID;
ControlFileLockId = (SPINLOCK) CNTLFILELOCKID;
#ifdef STABLE_MEMORY_STORAGE #ifdef STABLE_MEMORY_STORAGE
MMCacheLock = (SPINLOCK) MMCACHELOCKID; MMCacheLock = (SPINLOCK) MMCACHELOCKID;
#endif #endif
return TRUE; return;
} }
#endif /* HAS_TEST_AND_SET */ #endif /* HAS_TEST_AND_SET */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
* This is so that we can support more backends. (system-wide semaphore * This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95 * 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 <sys/time.h>
#include <unistd.h> #include <unistd.h>
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
#include "storage/proc.h" #include "storage/proc.h"
#include "utils/trace.h" #include "utils/trace.h"
static void HandleDeadLock(int sig); void HandleDeadLock(SIGNAL_ARGS);
static void ProcFreeAllSemaphores(void); static void ProcFreeAllSemaphores(void);
#define DeadlockCheckTimer pg_options[OPT_DEADLOCKTIMEOUT] #define DeadlockCheckTimer pg_options[OPT_DEADLOCKTIMEOUT]
...@@ -84,12 +84,6 @@ static void ProcFreeAllSemaphores(void); ...@@ -84,12 +84,6 @@ static void ProcFreeAllSemaphores(void);
*/ */
SPINLOCK ProcStructLock; SPINLOCK ProcStructLock;
/*
* For cleanup routines. Don't cleanup if the initialization
* has not happened.
*/
static bool ProcInitialized = FALSE;
static PROC_HDR *ProcGlobal = NULL; static PROC_HDR *ProcGlobal = NULL;
PROC *MyProc = NULL; PROC *MyProc = NULL;
...@@ -167,8 +161,9 @@ InitProcGlobal(IPCKey key, int maxBackends) ...@@ -167,8 +161,9 @@ InitProcGlobal(IPCKey key, int maxBackends)
PROC_NSEMS_PER_SET, PROC_NSEMS_PER_SET,
IPCProtection, IPCProtection,
IpcSemaphoreDefaultStartValue, IpcSemaphoreDefaultStartValue,
0, 0);
&semstat); if (semId < 0)
elog(FATAL, "InitProcGlobal: IpcSemaphoreCreate failed");
/* mark this sema set allocated */ /* mark this sema set allocated */
ProcGlobal->freeSemMap[i] = (1 << PROC_NSEMS_PER_SET); ProcGlobal->freeSemMap[i] = (1 << PROC_NSEMS_PER_SET);
} }
...@@ -189,12 +184,6 @@ InitProcess(IPCKey key) ...@@ -189,12 +184,6 @@ InitProcess(IPCKey key)
unsigned long location, unsigned long location,
myOffset; myOffset;
/* ------------------
* Routine called if deadlock timer goes off. See ProcSleep()
* ------------------
*/
pqsignal(SIGALRM, HandleDeadLock);
SpinAcquire(ProcStructLock); SpinAcquire(ProcStructLock);
/* attach to the free list */ /* attach to the free list */
...@@ -203,7 +192,7 @@ InitProcess(IPCKey key) ...@@ -203,7 +192,7 @@ InitProcess(IPCKey key)
if (!found) if (!found)
{ {
/* this should not happen. InitProcGlobal() is called before this. */ /* this should not happen. InitProcGlobal() is called before this. */
elog(ERROR, "InitProcess: Proc Header uninitialized"); elog(STOP, "InitProcess: Proc Header uninitialized");
} }
if (MyProc != NULL) if (MyProc != NULL)
...@@ -271,8 +260,7 @@ InitProcess(IPCKey key) ...@@ -271,8 +260,7 @@ InitProcess(IPCKey key)
PROC_NSEMS_PER_SET, PROC_NSEMS_PER_SET,
IPCProtection, IPCProtection,
IpcSemaphoreDefaultStartValue, IpcSemaphoreDefaultStartValue,
0, 0);
&semstat);
/* /*
* we might be reusing a semaphore that belongs to a dead backend. * we might be reusing a semaphore that belongs to a dead backend.
...@@ -316,14 +304,12 @@ InitProcess(IPCKey key) ...@@ -316,14 +304,12 @@ InitProcess(IPCKey key)
*/ */
location = MAKE_OFFSET(MyProc); location = MAKE_OFFSET(MyProc);
if ((!ShmemPIDLookup(MyProcPid, &location)) || (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; MyProc->errType = NO_ERROR;
SHMQueueElemInit(&(MyProc->links)); SHMQueueElemInit(&(MyProc->links));
on_shmem_exit(ProcKill, (caddr_t) MyProcPid); on_shmem_exit(ProcKill, (caddr_t) MyProcPid);
ProcInitialized = TRUE;
} }
/* /*
...@@ -755,8 +741,8 @@ ProcAddLock(SHM_QUEUE *elem) ...@@ -755,8 +741,8 @@ ProcAddLock(SHM_QUEUE *elem)
* up my semaphore. * up my semaphore.
* -------------------- * --------------------
*/ */
static void void
HandleDeadLock(int sig) HandleDeadLock(SIGNAL_ARGS)
{ {
LOCK *mywaitlock; LOCK *mywaitlock;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include "tcop/pquery.h" #include "tcop/pquery.h"
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "tcop/utility.h" #include "tcop/utility.h"
#include "storage/proc.h"
#include "utils/ps_status.h" #include "utils/ps_status.h"
#include "utils/temprel.h" #include "utils/temprel.h"
#include "utils/trace.h" #include "utils/trace.h"
...@@ -98,11 +99,20 @@ ...@@ -98,11 +99,20 @@
*/ */
/*static bool EnableRewrite = true; , never changes why have it*/ /*static bool EnableRewrite = true; , never changes why have it*/
CommandDest whereToSendOutput; CommandDest whereToSendOutput = Debug;
/* Define status buffer needed by PS_SET_STATUS */ /* Define status buffer needed by PS_SET_STATUS */
PS_DEFINE_BUFFER; 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 lockingOff;
extern int NBuffers; extern int NBuffers;
...@@ -115,21 +125,8 @@ char relname[80]; /* current relation name */ ...@@ -115,21 +125,8 @@ char relname[80]; /* current relation name */
/* note: these declarations had better match tcopprot.h */ /* note: these declarations had better match tcopprot.h */
DLLIMPORT sigjmp_buf Warn_restart; DLLIMPORT sigjmp_buf Warn_restart;
bool InError = true; bool InError = false;
bool ExitAfterAbort = false;
/*
* 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.
*/
extern int NBuffers; extern int NBuffers;
...@@ -773,6 +770,7 @@ handle_warn(SIGNAL_ARGS) ...@@ -773,6 +770,7 @@ handle_warn(SIGNAL_ARGS)
void void
quickdie(SIGNAL_ARGS) quickdie(SIGNAL_ARGS)
{ {
PG_SETMASK(&BlockSig);
elog(NOTICE, "Message from PostgreSQL backend:" elog(NOTICE, "Message from PostgreSQL backend:"
"\n\tThe Postmaster has informed me that some other backend" "\n\tThe Postmaster has informed me that some other backend"
" died abnormally and possibly corrupted shared memory." " died abnormally and possibly corrupted shared memory."
...@@ -787,13 +785,25 @@ quickdie(SIGNAL_ARGS) ...@@ -787,13 +785,25 @@ quickdie(SIGNAL_ARGS)
* storage. Just nail the windows shut and get out of town. * storage. Just nail the windows shut and get out of town.
*/ */
exit(0); exit(1);
} }
/*
* Abort transaction and exit
*/
void void
die(SIGNAL_ARGS) 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 */ /* signal handler for floating point exception */
...@@ -907,6 +917,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -907,6 +917,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
#endif #endif
DataDir = getenv("PGDATA"); DataDir = getenv("PGDATA");
SetProcessingMode(InitProcessing);
/* /*
* Try to get initial values for date styles and formats. Does not do * 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 * a complete job, but should be good enough for backend. Cannot call
...@@ -1265,10 +1277,68 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1265,10 +1277,68 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
break; break;
} }
/* ---------------- if (ShowStats &&
* get user name (needed now in case it is the default database name) (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 * and check command line validity
* ----------------
*/ */
SetPgUserName(); SetPgUserName();
userName = GetPgUserName(); userName = GetPgUserName();
...@@ -1281,10 +1351,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1281,10 +1351,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
usage(argv[0]); usage(argv[0]);
proc_exit(1); proc_exit(1);
} }
pq_init(); /* initialize libpq at backend startup */
whereToSendOutput = Remote;
BaseInit();
} }
else else
{ {
/* interactive case: database name can be last arg on command line */ /* interactive case: database name can be last arg on command line */
whereToSendOutput = Debug;
if (errs || argc - optind > 1) if (errs || argc - optind > 1)
{ {
usage(argv[0]); usage(argv[0]);
...@@ -1298,23 +1372,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1298,23 +1372,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
argv[0]); argv[0]);
proc_exit(1); proc_exit(1);
} }
} BaseInit();
sprintf(XLogDir, "%s%cpg_xlog", DataDir, SEP_CHAR);
if (ShowStats && sprintf(ControlFilePath, "%s%cpg_control", DataDir, SEP_CHAR);
(ShowParserStats || ShowPlannerStats || ShowExecutorStats)) StartupXLOG();
{
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);
} }
/* /*
...@@ -1367,19 +1428,15 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1367,19 +1428,15 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
remote_info = remote_host = "unknown"; remote_info = remote_host = "unknown";
break; break;
} }
} /*
* Set process params for ps
/* ----------------
* set process params for ps
* ----------------
*/ */
if (IsUnderPostmaster)
{
PS_INIT_STATUS(real_argc, real_argv, argv[0], PS_INIT_STATUS(real_argc, real_argv, argv[0],
remote_info, userName, DBName); remote_info, userName, DBName);
PS_SET_STATUS("startup"); PS_SET_STATUS("startup");
} }
/* ---------------- /* ----------------
* print flags * print flags
* ---------------- * ----------------
...@@ -1409,23 +1466,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1409,23 +1466,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
} }
} }
/* ----------------
* 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) if (Verbose)
TPRINTF(TRACE_VERBOSE, "InitPostgres"); TPRINTF(TRACE_VERBOSE, "InitPostgres");
...@@ -1445,30 +1489,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1445,30 +1489,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
parser_input = makeStringInfo(); /* initialize input buffer */ 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 * Send this backend's cancellation info to the frontend.
* 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(SIGUSR1, quickdie);
pqsignal(SIGUSR2, Async_NotifyHandler); /* flush also sinval cache */
pqsignal(SIGCHLD, SIG_IGN); /* ignored, sent by LockOwners */
pqsignal(SIGFPE, FloatExceptionHandler);
if (whereToSendOutput == Remote && if (whereToSendOutput == Remote &&
PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
{ {
...@@ -1485,40 +1508,41 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1485,40 +1508,41 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); 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 * Initialize the deferred trigger manager
* ----------------
*/ */
if (DeferredTriggerInit() != 0) if (DeferredTriggerInit() != 0)
ExitPostgres(1); ExitPostgres(1);
/* ---------------- /*
* POSTGRES main processing loop begins here * POSTGRES main processing loop begins here
* *
* if an exception is encountered, processing resumes here * If an exception is encountered, processing resumes here
* so we abort the current transaction and start a new one. * so we abort the current transaction and start a new one.
*
* Note: elog(ERROR) does a siglongjmp() to transfer control here.
* See comments with the declaration of InError, above.
* ----------------
*/ */
SetProcessingMode(NormalProcessing);
if (sigsetjmp(Warn_restart, 1) != 0) if (sigsetjmp(Warn_restart, 1) != 0)
{ {
InError = true;
time(&tim); time(&tim);
if (Verbose) if (Verbose)
TPRINTF(TRACE_VERBOSE, "AbortCurrentTransaction"); TPRINTF(TRACE_VERBOSE, "AbortCurrentTransaction");
AbortCurrentTransaction(); AbortCurrentTransaction();
InError = false;
if (ExitAfterAbort)
{
ProcReleaseLocks(); /* Just to be sure... */
ExitPostgres(0);
}
} }
InError = false; PG_SETMASK(&UnBlockSig);
/* /*
* Non-error queries loop here. * Non-error queries loop here.
...@@ -1636,6 +1660,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1636,6 +1660,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
*/ */
case 'X': case 'X':
case EOF: case EOF:
if (!IsUnderPostmaster)
ShutdownXLOG();
pq_close(); pq_close();
proc_exit(0); proc_exit(0);
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
extern int errno; extern int errno;
extern int sys_nerr; extern int sys_nerr;
extern CommandDest whereToSendOutput;
#ifdef USE_SYSLOG #ifdef USE_SYSLOG
/* /*
...@@ -107,6 +108,19 @@ elog(int lev, const char *fmt, ...) ...@@ -107,6 +108,19 @@ elog(int lev, const char *fmt, ...)
if (lev <= DEBUG && Debugfile < 0) if (lev <= DEBUG && Debugfile < 0)
return; /* ignore debug msgs if noplace to send */ 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 */ /* choose message prefix and indent level */
switch (lev) switch (lev)
{ {
...@@ -304,7 +318,7 @@ elog(int lev, const char *fmt, ...) ...@@ -304,7 +318,7 @@ elog(int lev, const char *fmt, ...)
#ifndef PG_STANDALONE #ifndef PG_STANDALONE
if (lev > DEBUG && IsUnderPostmaster) if (lev > DEBUG && whereToSendOutput == Remote)
{ {
/* Send IPC message to the front-end program */ /* Send IPC message to the front-end program */
char msgtype; char msgtype;
...@@ -336,7 +350,7 @@ elog(int lev, const char *fmt, ...) ...@@ -336,7 +350,7 @@ elog(int lev, const char *fmt, ...)
pq_flush(); pq_flush();
} }
if (lev > DEBUG && ! IsUnderPostmaster) if (lev > DEBUG && whereToSendOutput != Remote)
{ {
/* We are running as an interactive backend, so just send /* We are running as an interactive backend, so just send
* the message to stderr. * the message to stderr.
...@@ -355,30 +369,23 @@ elog(int lev, const char *fmt, ...) ...@@ -355,30 +369,23 @@ elog(int lev, const char *fmt, ...)
/* /*
* Perform error recovery action as specified by lev. * Perform error recovery action as specified by lev.
*/ */
if (lev == ERROR) if (lev == ERROR || lev == FATAL)
{ {
if (InError) if (InError)
{ {
/* error reported during error recovery; don't loop forever */ /* error reported during error recovery; don't loop forever */
elog(REALLYFATAL, "elog: error during error recovery, giving up!"); elog(REALLYFATAL, "elog: error during error recovery, giving up!");
} }
/* exit to main loop */ InError = true;
ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */ ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
siglongjmp(Warn_restart, 1);
}
if (lev == FATAL) if (lev == FATAL)
{ {
/* if (IsInitProcessingMode())
* Assume that if we have detected the failure we can exit with a ExitPostgres(0);
* normal exit status. This will prevent the postmaster from ExitAfterAbort = true;
* cleaning up when it's not needed. }
*/ /* exit to main loop */
fflush(stdout); siglongjmp(Warn_restart, 1);
fflush(stderr);
ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
ProcReleaseLocks(); /* get rid of real locks we hold */
proc_exit(0);
} }
if (lev > FATAL) if (lev > FATAL)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -133,20 +133,7 @@ StatusPostmasterExit(int status) ...@@ -133,20 +133,7 @@ StatusPostmasterExit(int status)
* processing mode support stuff (used to be in pmod.c) * processing mode support stuff (used to be in pmod.c)
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static ProcessingMode Mode = NoProcessing; static ProcessingMode Mode = InitProcessing;
#ifdef NOT_USED
/*
* IsNoProcessingMode
* True iff processing mode is NoProcessing.
*/
bool
IsNoProcessingMode()
{
return (bool) (Mode == NoProcessing);
}
#endif
/* /*
* IsBootstrapProcessingMode * IsBootstrapProcessingMode
...@@ -186,13 +173,13 @@ IsNormalProcessingMode() ...@@ -186,13 +173,13 @@ IsNormalProcessingMode()
* BadArg if called with invalid mode. * BadArg if called with invalid mode.
* *
* Note: * Note:
* Mode is NoProcessing before the first time this is called. * Mode is InitProcessing before the first time this is called.
*/ */
void void
SetProcessingMode(ProcessingMode mode) SetProcessingMode(ProcessingMode mode)
{ {
AssertArg(mode == NoProcessing || mode == BootstrapProcessing || AssertArg(mode == BootstrapProcessing || mode == InitProcessing ||
mode == InitProcessing || mode == NormalProcessing); mode == NormalProcessing);
Mode = mode; Mode = mode;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* InitPostgres() is the function called from PostgresMain * InitPostgres() is the function called from PostgresMain
...@@ -53,12 +53,13 @@ ...@@ -53,12 +53,13 @@
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#endif #endif
void BaseInit(void);
static void VerifySystemDatabase(void); static void VerifySystemDatabase(void);
static void VerifyMyDatabase(void); static void VerifyMyDatabase(void);
static void ReverifyMyDatabase(char *name); static void ReverifyMyDatabase(char *name);
static void InitCommunication(void); static void InitCommunication(void);
static void InitMyDatabaseInfo(char *name); static void InitMyDatabaseInfo(char *name);
static void InitStdio(void);
static void InitUserid(void); static void InitUserid(void);
...@@ -385,37 +386,6 @@ InitCommunication() ...@@ -385,37 +386,6 @@ InitCommunication()
{ {
if (MyBackendTag == -1) if (MyBackendTag == -1)
elog(FATAL, "InitCommunication: missing POSTID"); 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) else if (IsUnderPostmaster)
{ {
...@@ -439,12 +409,6 @@ InitCommunication() ...@@ -439,12 +409,6 @@ InitCommunication()
* initialize shared memory and semaphores appropriately. * initialize shared memory and semaphores appropriately.
* ---------------- * ----------------
*/ */
#ifdef EMULATE_UNDER_POSTMASTER
forcesharedmemory:
#endif
if (!IsUnderPostmaster) /* postmaster already did this */ if (!IsUnderPostmaster) /* postmaster already did this */
{ {
PostgresIpcKey = key; PostgresIpcKey = key;
...@@ -452,21 +416,6 @@ forcesharedmemory: ...@@ -452,21 +416,6 @@ forcesharedmemory:
} }
} }
/* --------------------------------
* 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 * InitPostgres
* Initialize POSTGRES. * Initialize POSTGRES.
...@@ -477,8 +426,6 @@ InitStdio() ...@@ -477,8 +426,6 @@ InitStdio()
*/ */
extern int NBuffers; extern int NBuffers;
bool PostgresIsInitialized = false;
int lockingOff = 0; /* backend -L switch */ int lockingOff = 0; /* backend -L switch */
/* /*
...@@ -488,37 +435,11 @@ InitPostgres(char *name) /* database name */ ...@@ -488,37 +435,11 @@ InitPostgres(char *name) /* database name */
{ {
bool bootstrap; /* true if BootstrapProcessing */ bool bootstrap; /* true if BootstrapProcessing */
/* ---------------- /*
* see if we're running in BootstrapProcessing mode * See if we're running in BootstrapProcessing mode
* ----------------
*/ */
bootstrap = IsBootstrapProcessingMode(); 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 * initialize the backend local portal stack used by
* internal PQ function calls. see src/lib/libpq/be-dumpdata.c * internal PQ function calls. see src/lib/libpq/be-dumpdata.c
...@@ -528,14 +449,6 @@ InitPostgres(char *name) /* database name */ ...@@ -528,14 +449,6 @@ InitPostgres(char *name) /* database name */
*/ */
be_portalinit(); be_portalinit();
/* ----------------
* attach to shared memory and semaphores, and initialize our
* input/output/debugging file descriptors.
* ----------------
*/
InitCommunication();
InitStdio();
/* /*
* initialize the local buffer manager * initialize the local buffer manager
*/ */
...@@ -574,13 +487,9 @@ InitPostgres(char *name) /* database name */ ...@@ -574,13 +487,9 @@ InitPostgres(char *name) /* database name */
* Will try that, but may not work... - thomas 1997-11-01 * 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.
/* ----------------
* initialize the transaction system and the relation descriptor cache.
* Note we have to make certain the lock manager is off while we do this. * Note we have to make certain the lock manager is off while we do this.
* ----------------
*/ */
AmiTransactionOverride(IsBootstrapProcessingMode()); AmiTransactionOverride(IsBootstrapProcessingMode());
LockDisable(true); LockDisable(true);
...@@ -598,20 +507,18 @@ InitPostgres(char *name) /* database name */ ...@@ -598,20 +507,18 @@ InitPostgres(char *name) /* database name */
LockDisable(false); LockDisable(false);
/* ---------------- /*
* Set up my per-backend PROC struct in shared memory. * Set up my per-backend PROC struct in shared memory.
* ----------------
*/ */
InitProcess(PostgresIpcKey); InitProcess(PostgresIpcKey);
/* ---------------- /*
* Initialize my entry in the shared-invalidation manager's * Initialize my entry in the shared-invalidation manager's
* array of per-backend data. (Formerly this came before * array of per-backend data. (Formerly this came before
* InitProcess, but now it must happen after, because it uses * InitProcess, but now it must happen after, because it uses
* MyProc.) Once I have done this, I am visible to other backends! * 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(); InitSharedInvalidationState();
...@@ -622,16 +529,14 @@ InitPostgres(char *name) /* database name */ ...@@ -622,16 +529,14 @@ InitPostgres(char *name) /* database name */
MyBackendId); MyBackendId);
} }
/* ---------------- /*
* initialize the access methods. * Initialize the access methods.
* Does not touch files (?) - thomas 1997-11-01 * Does not touch files (?) - thomas 1997-11-01
* ----------------
*/ */
initam(); initam();
/* ---------------- /*
* initialize all the system catalog caches. * Initialize all the system catalog caches.
* ----------------
*/ */
zerocaches(); zerocaches();
...@@ -641,34 +546,19 @@ InitPostgres(char *name) /* database name */ ...@@ -641,34 +546,19 @@ InitPostgres(char *name) /* database name */
*/ */
InitCatalogCache(); InitCatalogCache();
/* ---------------- /*
* set ourselves to the proper user id and figure out our postgres * 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 * user id. If we ever add security so that we check for valid
* postgres users, we might do it here. * postgres users, we might do it here.
* ----------------
*/ */
InitUserid(); InitUserid();
/* ---------------- /*
* initialize local data in cache invalidation stuff * Initialize local data in cache invalidation stuff
* ----------------
*/ */
if (!bootstrap) if (!bootstrap)
InitLocalInvalidateData(); 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) if (lockingOff)
LockDisable(true); LockDisable(true);
...@@ -680,3 +570,30 @@ InitPostgres(char *name) /* database name */ ...@@ -680,3 +570,30 @@ InitPostgres(char *name) /* database name */
if (!bootstrap) if (!bootstrap)
ReverifyMyDatabase(name); 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();
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
#include "utils/tqual.h" #include "utils/tqual.h"
extern bool PostgresIsInitialized;
SnapshotData SnapshotDirtyData; SnapshotData SnapshotDirtyData;
Snapshot SnapshotDirty = &SnapshotDirtyData; Snapshot SnapshotDirty = &SnapshotDirtyData;
...@@ -194,17 +192,6 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) ...@@ -194,17 +192,6 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple)
if (AMI_OVERRIDE) if (AMI_OVERRIDE)
return true; 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_COMMITTED))
{ {
if (tuple->t_infomask & HEAP_XMIN_INVALID) if (tuple->t_infomask & HEAP_XMIN_INVALID)
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
# #
# #
# IDENTIFICATION # 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 $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -300,6 +300,12 @@ else ...@@ -300,6 +300,12 @@ else
mkdir $PGDATA/base mkdir $PGDATA/base
if [ $? -ne 0 ]; then exit 5; fi if [ $? -ne 0 ]; then exit 5; fi
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
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
...@@ -316,6 +322,7 @@ else ...@@ -316,6 +322,7 @@ else
fi fi
BACKENDARGS="-boot -C -F -D$PGDATA $BACKEND_TALK_ARG" 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" echo "Creating template database in $PGDATA/base/template1"
[ "$debug" -ne 0 ] && echo "Running: postgres $BACKENDARGS template1" [ "$debug" -ne 0 ] && echo "Running: postgres $BACKENDARGS template1"
...@@ -323,7 +330,7 @@ echo "Creating template database in $PGDATA/base/template1" ...@@ -323,7 +330,7 @@ echo "Creating template database in $PGDATA/base/template1"
cat $TEMPLATE \ cat $TEMPLATE \
| sed -e "s/postgres PGUID/$POSTGRES_SUPERUSERNAME $POSTGRES_SUPERUID/" \ | sed -e "s/postgres PGUID/$POSTGRES_SUPERUSERNAME $POSTGRES_SUPERUID/" \
-e "s/PGUID/$POSTGRES_SUPERUID/" \ -e "s/PGUID/$POSTGRES_SUPERUID/" \
| postgres $BACKENDARGS template1 | postgres $FIRSTRUN template1
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "$CMDNAME: could not create template database" echo "$CMDNAME: could not create template database"
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* This shouldn't be in libpq, but the monitor and some other * This shouldn't be in libpq, but the monitor and some other
...@@ -17,6 +17,28 @@ ...@@ -17,6 +17,28 @@
#ifndef PQSIGNAL_H #ifndef PQSIGNAL_H
#define 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); typedef void (*pqsigfunc) (int);
extern pqsigfunc pqsignal(int signo, pqsigfunc func); extern pqsigfunc pqsignal(int signo, pqsigfunc func);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* some of the information in this file will be moved to * some of the information in this file will be moved to
...@@ -143,28 +143,25 @@ extern int CheckPathAccess(char *path, char *name, int open_mode); ...@@ -143,28 +143,25 @@ extern int CheckPathAccess(char *path, char *name, int open_mode);
*****************************************************************************/ *****************************************************************************/
/* /*
* Description: * Description:
* There are four processing modes in POSTGRES. They are NoProcessing * There are three processing modes in POSTGRES. They are
* or "none," BootstrapProcessing or "bootstrap," InitProcessing or * "BootstrapProcessing or "bootstrap," InitProcessing or
* "initialization," and NormalProcessing or "normal." * "initialization," and NormalProcessing or "normal."
* *
* If a POSTGRES binary is in normal mode, then all code may be executed * The first two processing modes are used during special times. When the
* 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
* system state indicates bootstrap processing, transactions are all given * 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. * is used during the initial generation of template databases.
* *
* Finally, the execution state is in initialization mode until all normal * Initialization mode until all normal initialization is complete.
* initialization is complete. Some code behaves differently when executed in * Some code behaves differently when executed in this mode to enable
* this mode to enable system bootstrapping. * system bootstrapping.
*
* If a POSTGRES binary is in normal mode, then all code may be executed
* normally.
*/ */
typedef enum ProcessingMode typedef enum ProcessingMode
{ {
NoProcessing, /* "nothing" can be done */
BootstrapProcessing, /* bootstrap creation of template database */ BootstrapProcessing, /* bootstrap creation of template database */
InitProcessing, /* initializing system */ InitProcessing, /* initializing system */
NormalProcessing /* normal processing */ NormalProcessing /* normal processing */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* This file is very architecture-specific. This stuff should actually * This file is very architecture-specific. This stuff should actually
...@@ -79,7 +79,7 @@ extern void on_exit_reset(void); ...@@ -79,7 +79,7 @@ extern void on_exit_reset(void);
extern IpcSemaphoreId IpcSemaphoreCreate(IpcSemaphoreKey semKey, extern IpcSemaphoreId IpcSemaphoreCreate(IpcSemaphoreKey semKey,
int semNum, int permission, int semStartValue, int semNum, int permission, int semStartValue,
int removeOnExit, int *status); int removeOnExit);
extern void IpcSemaphoreKill(IpcSemaphoreKey key); extern void IpcSemaphoreKill(IpcSemaphoreKey key);
extern void IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock); extern void IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock);
extern void IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock); extern void IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock);
...@@ -105,6 +105,8 @@ typedef enum _LockId_ ...@@ -105,6 +105,8 @@ typedef enum _LockId_
BUFMGRLOCKID, BUFMGRLOCKID,
LOCKLOCKID, LOCKLOCKID,
OIDGENLOCKID, OIDGENLOCKID,
XIDGENLOCKID,
CNTLFILELOCKID,
SHMEMLOCKID, SHMEMLOCKID,
SHMEMINDEXLOCKID, SHMEMINDEXLOCKID,
LOCKMGRLOCKID, LOCKMGRLOCKID,
...@@ -147,6 +149,8 @@ typedef enum _LockId_ ...@@ -147,6 +149,8 @@ typedef enum _LockId_
PROCSTRUCTLOCKID, PROCSTRUCTLOCKID,
OIDGENLOCKID, OIDGENLOCKID,
XIDGENLOCKID,
CNTLFILELOCKID,
FIRSTFREELOCKID FIRSTFREELOCKID
} _LockId_; } _LockId_;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
typedef int SPINLOCK; typedef int SPINLOCK;
extern bool CreateSpinlocks(IPCKey key); extern void CreateSpinlocks(IPCKey key);
extern bool InitSpinLocks(int init, IPCKey key); extern void InitSpinLocks(void);
extern void SpinAcquire(SPINLOCK lockid); extern void SpinAcquire(SPINLOCK lockid);
extern void SpinRelease(SPINLOCK lockid); extern void SpinRelease(SPINLOCK lockid);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 * OLD COMMENTS
* This file was created so that other c files could get the two * This file was created so that other c files could get the two
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#endif #endif
extern DLLIMPORT sigjmp_buf Warn_restart; extern DLLIMPORT sigjmp_buf Warn_restart;
extern bool InError; extern bool InError;
extern bool ExitAfterAbort;
#ifndef BOOTSTRAP_INCLUDE #ifndef BOOTSTRAP_INCLUDE
extern List *pg_parse_and_plan(char *query_string, Oid *typev, int nargs, extern List *pg_parse_and_plan(char *query_string, Oid *typev, int nargs,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment