diff -rcN postgresql_with_9fujii_patch/src/backend/access/transam/xlog.c postgresql_with_patch/src/backend/access/transam/xlog.c *** postgresql_with_9fujii_patch/src/backend/access/transam/xlog.c 2011-10-06 06:06:19.000000000 +0900 --- postgresql_with_patch/src/backend/access/transam/xlog.c 2011-10-19 07:02:07.000000000 +0900 *************** *** 364,369 **** --- 364,372 ---- bool exclusiveBackup; int nonExclusiveBackups; XLogRecPtr lastBackupStart; + + /* the startup or the walwriter is logged to its own FPW */ + bool fullPageWrites; } XLogCtlInsert; /* *************** *** 453,458 **** --- 456,464 ---- bool recoveryPause; slock_t info_lck; /* locks shared variables shown above */ + + /* latest LSN that has recovered a WAL which fpw is 'off' */ + XLogRecPtr lastFpwDisabledLSN; } XLogCtlData; static XLogCtlData *XLogCtl = NULL; *************** *** 759,769 **** /* * Decide if we need to do full-page writes in this XLOG record: true if ! * full_page_writes is on or we have a PITR request for it. Since we ! * don't yet have the insert lock, forcePageWrites could change under us, ! * but we'll recheck it once we have the lock. */ ! doPageWrites = fullPageWrites || Insert->forcePageWrites; INIT_CRC32(rdata_crc); len = 0; --- 765,776 ---- /* * Decide if we need to do full-page writes in this XLOG record: true if ! * full_page_writes in shared-memory is on or we have a PITR request for ! * it. Since we don't yet have the insert lock, fullPageWrites or ! * forcePageWrites could change under us, but we'll recheck it once we ! * have the lock. */ ! doPageWrites = Insert->fullPageWrites || Insert->forcePageWrites; INIT_CRC32(rdata_crc); len = 0; *************** *** 904,915 **** } /* ! * Also check to see if forcePageWrites was just turned on; if we weren't ! * already doing full-page writes then go back and recompute. (If it was ! * just turned off, we could recompute the record without full pages, but ! * we choose not to bother.) */ ! if (Insert->forcePageWrites && !doPageWrites) { /* Oops, must redo it with full-page data */ LWLockRelease(WALInsertLock); --- 911,922 ---- } /* ! * Also check to see if fullPageWrites or forcePageWrites was just ! * turned on; if we weren't already doing full-page writes then go back ! * and recompute. (If it was just turned off, we could recompute the ! * record without full pages, but we choose not to bother.) */ ! if ((Insert->fullPageWrites || Insert->forcePageWrites) && !doPageWrites) { /* Oops, must redo it with full-page data */ LWLockRelease(WALInsertLock); *************** *** 7001,7006 **** --- 7008,7020 ---- XLogReportParameters(); /* + * The startup updates FPW after REDO. ReportFpwParameters() is called + * here because it is not called on checkpoint after REDO. + * It is safe because we cannot update data during the startup running. + */ + ReportFpwParameters(REPORT_ON_STARTUP); + + /* * All done. Allow backends to write WAL. (Although the bool flag is * probably atomic in itself, we use the info_lck here to ensure that * there are no race conditions concerning visibility of other recent *************** *** 7856,7862 **** --- 7870,7885 ---- * Update checkPoint.nextXid since we have a later value */ if (!shutdown && XLogStandbyInfoActive()) + { LogStandbySnapshot(&checkPoint.oldestActiveXid, &checkPoint.nextXid); + + /* + * The bgwriter writes WAL of FPW at checkpoint. But does not at shutdown. + * Because ReportFpwParameters() is always called at the end of startup + * process, it does not need to be called at shutdown. + */ + ReportFpwParameters(REPORT_ON_BGWRITER); + } else checkPoint.oldestActiveXid = InvalidTransactionId; *************** *** 8636,8641 **** --- 8659,8681 ---- /* Check to see if any changes to max_connections give problems */ CheckRequiredParameterValues(); } + else if (info == XLOG_FPW_CHANGE) + { + /* use volatile pointer to prevent code rearrangement */ + volatile XLogCtlData *xlogctl = XLogCtl; + + bool fpw; + + memcpy(&fpw, XLogRecGetData(record), sizeof(fpw)); + + /* record the LSN when FPW is false on master */ + if (!fpw) + { + SpinLockAcquire(&xlogctl->info_lck); + xlogctl->lastFpwDisabledLSN = lsn; + SpinLockRelease(&xlogctl->info_lck); + } + } } void *************** *** 8717,8722 **** --- 8757,8770 ---- xlrec.max_locks_per_xact, wal_level_str); } + else if (info == XLOG_FPW_CHANGE) + { + bool fpw; + + memcpy(&fpw, rec, sizeof(fpw)); + appendStringInfo(buf, "fpw change: full_page_writes=%s", + fpw ? "true" : "false"); + } else appendStringInfo(buf, "UNKNOWN"); } *************** *** 8933,8938 **** --- 8981,8987 ---- bool recovery_in_progress = false; XLogRecPtr checkpointloc; XLogRecPtr startpoint; + XLogRecPtr lastFpwDisabledLSN; pg_time_t stamp_time; char strfbuf[128]; char xlogfilename[MAXFNAMELEN]; *************** *** 9089,9094 **** --- 9138,9161 ---- gotUniqueStartpoint = true; } while (!gotUniqueStartpoint); + /* + * check whether the master's FPW is 'off' since latest CHECKPOINT. + */ + if (recovery_in_progress) + { + /* use volatile pointer to prevent code rearrangement */ + volatile XLogCtlData *xlogctl = XLogCtl; + + SpinLockAcquire(&xlogctl->info_lck); + lastFpwDisabledLSN = xlogctl->lastFpwDisabledLSN; + SpinLockRelease(&xlogctl->info_lck); + + if (XLByteLE(startpoint, lastFpwDisabledLSN)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("WAL generated with full_page_writes=off was replayed since latest checkpoint"))); + } + XLByteToSeg(startpoint, _logId, _logSeg); XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg); *************** *** 9233,9238 **** --- 9300,9306 ---- bool recovery_in_progress = false; XLogRecPtr startpoint; XLogRecPtr stoppoint; + XLogRecPtr lastFpwDisabledLSN; XLogRecData rdata; pg_time_t stamp_time; char strfbuf[128]; *************** *** 9372,9377 **** --- 9440,9461 ---- "though pg_start_backup() was executed during recovery"), errhint("The database backup will not be usable."))); + /* check whether the master's FPW is 'off' since pg_start_backup. */ + if (recovery_in_progress) + { + /* use volatile pointer to prevent code rearrangement */ + volatile XLogCtlData *xlogctl = XLogCtl; + + SpinLockAcquire(&xlogctl->info_lck); + lastFpwDisabledLSN = xlogctl->lastFpwDisabledLSN; + SpinLockRelease(&xlogctl->info_lck); + + if (XLByteLE(startpoint, lastFpwDisabledLSN)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("WAL generated with full_page_writes=off was replayed during online backup"))); + } + /* * During recovery, we don't write an end-of-backup record. We can * assume that pg_control was backed up just before pg_stop_backup() *************** *** 10743,10745 **** --- 10827,10879 ---- { SetLatch(&XLogCtl->recoveryWakeupLatch); } + + /* + * Insert a WAL of XLOG_FPW_CHANGE or update to the shared memory. + * The called timing is at checkpoint, at the end of startup or at receiving + * SIGHUP on walwriter. + * checkpoint: insert, but not update. + * startup: insert and update. + * walwriter: insert and update if FPW was changed. + */ + void + ReportFpwParameters(int updatetiming) + { + bool fpw = fullPageWrites; + + if (updatetiming == REPORT_ON_BGWRITER) + { + LWLockAcquire(WALInsertLock, LW_EXCLUSIVE); + fpw = XLogCtl->Insert.fullPageWrites; + LWLockRelease(WALInsertLock); + } + + if (updatetiming <= REPORT_ON_STARTUP || + (updatetiming == REPORT_ON_WALWRITER && fpw != XLogCtl->Insert.fullPageWrites)) + { + /* + * insert own fpw to a WAL. However, it does not perform + * when wal_level is not 'hotstandby' or fpw is same as shared-memory. + */ + if (XLogStandbyInfoActive()) + { + XLogRecData rdata; + bool record = fullPageWrites; + + rdata.buffer = InvalidBuffer; + rdata.data = (char *) &record; + rdata.len = sizeof(record); + rdata.next = NULL; + + XLogInsert(RM_XLOG_ID, XLOG_FPW_CHANGE, &rdata); + } + + /* update own fpw in shared-memory when it has managed fpw */ + if (updatetiming >= REPORT_ON_STARTUP) + { + LWLockAcquire(WALInsertLock, LW_EXCLUSIVE); + XLogCtl->Insert.fullPageWrites = fullPageWrites; + LWLockRelease(WALInsertLock); + } + } + } diff -rcN postgresql_with_9fujii_patch/src/backend/postmaster/walwriter.c postgresql_with_patch/src/backend/postmaster/walwriter.c *** postgresql_with_9fujii_patch/src/backend/postmaster/walwriter.c 2011-10-06 06:05:45.000000000 +0900 --- postgresql_with_patch/src/backend/postmaster/walwriter.c 2011-10-19 07:02:07.000000000 +0900 *************** *** 216,221 **** --- 216,228 ---- PG_SETMASK(&UnBlockSig); /* + * After the startup process, the walwriter manages the FPW. Because + * the walwriter may have not received a SIGHUP then, it updates the FPW + * when wal_level is hotstandby. + */ + ReportFpwParameters(REPORT_ON_WALWRITER); + + /* * Loop forever */ for (;;) *************** *** 236,241 **** --- 243,254 ---- { got_SIGHUP = false; ProcessConfigFile(PGC_SIGHUP); + + /* + * The walwriter manages the FPW. When the walwriter has received + * a SIGHUP, when wal_level is hotstandby, it updates the FPW. + */ + ReportFpwParameters(REPORT_ON_WALWRITER); } if (shutdown_requested) { diff -rcN postgresql_with_9fujii_patch/src/include/access/xlog.h postgresql_with_patch/src/include/access/xlog.h *** postgresql_with_9fujii_patch/src/include/access/xlog.h 2011-10-06 06:05:45.000000000 +0900 --- postgresql_with_patch/src/include/access/xlog.h 2011-10-19 07:02:07.000000000 +0900 *************** *** 208,213 **** --- 208,224 ---- } WalLevel; extern int wal_level; + /* + * The place of updating xlog parameter. + * If it is backend then this means a timing for CHECKPOINT. + */ + typedef enum + { + REPORT_ON_BGWRITER = 0, + REPORT_ON_STARTUP, + REPORT_ON_WALWRITER + } XLogParemeterUpdate; + #define XLogArchivingActive() (XLogArchiveMode && wal_level >= WAL_LEVEL_ARCHIVE) #define XLogArchiveCommandSet() (XLogArchiveCommand[0] != '\0') *************** *** 316,321 **** --- 327,333 ---- extern void StartupProcessMain(void); extern bool CheckPromoteSignal(void); extern void WakeupRecovery(void); + extern void ReportFpwParameters(int updatetiming); /* * Starting/stopping a base backup diff -rcN postgresql_with_9fujii_patch/src/include/catalog/pg_control.h postgresql_with_patch/src/include/catalog/pg_control.h *** postgresql_with_9fujii_patch/src/include/catalog/pg_control.h 2011-10-06 06:06:19.000000000 +0900 --- postgresql_with_patch/src/include/catalog/pg_control.h 2011-10-19 07:02:07.000000000 +0900 *************** *** 60,65 **** --- 60,66 ---- #define XLOG_BACKUP_END 0x50 #define XLOG_PARAMETER_CHANGE 0x60 #define XLOG_RESTORE_POINT 0x70 + #define XLOG_FPW_CHANGE 0x80 /*