diff -rcN postgresql/src/backend/access/transam/xlog.c postgresql_with_patch/src/backend/access/transam/xlog.c *** postgresql/src/backend/access/transam/xlog.c 2011-08-03 05:18:32.000000000 +0900 --- postgresql_with_patch/src/backend/access/transam/xlog.c 2011-08-03 19:03:00.000000000 +0900 *************** *** 6053,6059 **** ereport(LOG, (errmsg("database system was interrupted while in recovery at log time %s", str_time(ControlFile->checkPointCopy.time)), ! errhint("If this has occurred more than once some data might be corrupted" " and you might need to choose an earlier recovery target."))); else if (ControlFile->state == DB_IN_PRODUCTION) ereport(LOG, --- 6053,6059 ---- ereport(LOG, (errmsg("database system was interrupted while in recovery at log time %s", str_time(ControlFile->checkPointCopy.time)), ! errhint("If this has occurred more than once some data might be corrupted unless take backup from slave" " and you might need to choose an earlier recovery target."))); else if (ControlFile->state == DB_IN_PRODUCTION) ereport(LOG, *************** *** 6299,6304 **** --- 6299,6318 ---- /* use volatile pointer to prevent code rearrangement */ volatile XLogCtlData *xlogctl = XLogCtl; + /* + * get minRecoveryPoint before the value is changed for + * getting backup on standby server. + * check the result, set to pg_control. + */ + XLogRecPtr prevminRecoveryPoint = ControlFile->minRecoveryPoint; + if (!ControlFile->backupserver) + { + if (prevminRecoveryPoint.xlogid == 0 && prevminRecoveryPoint.xrecoff == 0) + ControlFile->backupserver = BACKUPSERVER_MASTER; + else + ControlFile->backupserver = BACKUPSERVER_SLAVE; + } + /* * Update pg_control to show that we are recovering and to show the * selected checkpoint as the place we are starting from. We also mark *************** *** 6607,6612 **** --- 6621,6646 ---- /* Pop the error context stack */ error_context_stack = errcontext.previous; + /* + * Check whether to reach minRecoveryPoint when getting backup + * on standby server. + */ + if (ControlFile->backupserver == BACKUPSERVER_SLAVE) + { + if (XLByteLE(prevminRecoveryPoint, EndRecPtr)) + { + elog(DEBUG1, "end of backup reached in the control file"); + + LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); + + MemSet(&ControlFile->backupStartPoint, 0, sizeof(XLogRecPtr)); + ControlFile->backupserver = BACKUPSERVER_NONE; + UpdateControlFile(); + + LWLockRelease(ControlFileLock); + } + } + /* * Update shared recoveryLastRecPtr after this record has been * replayed. *************** *** 8402,8408 **** * never arrive. */ if (InArchiveRecovery && ! !XLogRecPtrIsInvalid(ControlFile->backupStartPoint)) ereport(ERROR, (errmsg("online backup was canceled, recovery cannot continue"))); --- 8436,8443 ---- * never arrive. */ if (InArchiveRecovery && ! !XLogRecPtrIsInvalid(ControlFile->backupStartPoint) && ! ControlFile->backupserver == BACKUPSERVER_MASTER) ereport(ERROR, (errmsg("online backup was canceled, recovery cannot continue"))); *************** *** 8531,8536 **** --- 8566,8572 ---- if (XLByteLT(ControlFile->minRecoveryPoint, lsn)) ControlFile->minRecoveryPoint = lsn; MemSet(&ControlFile->backupStartPoint, 0, sizeof(XLogRecPtr)); + ControlFile->backupserver = BACKUPSERVER_NONE; UpdateControlFile(); LWLockRelease(ControlFileLock); *************** *** 8864,8869 **** --- 8900,8906 ---- do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile) { bool exclusive = (labelfile == NULL); + bool duringrecovery = false; XLogRecPtr checkpointloc; XLogRecPtr startpoint; pg_time_t stamp_time; *************** *** 8881,8892 **** errmsg("must be superuser or replication role to run a backup"))); if (RecoveryInProgress()) ! ereport(ERROR, ! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), ! errmsg("recovery is in progress"), ! errhint("WAL control functions cannot be executed during recovery."))); ! if (!XLogIsNeeded()) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("WAL level not sufficient for making an online backup"), --- 8918,8926 ---- errmsg("must be superuser or replication role to run a backup"))); if (RecoveryInProgress()) ! duringrecovery = true; ! if (!XLogIsNeeded() && !duringrecovery) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("WAL level not sufficient for making an online backup"), *************** *** 8909,8915 **** * directory was not included in the base backup and the WAL archive was * cleared too before starting the backup. */ ! RequestXLogSwitch(); /* * Mark backup active in shared memory. We must do full-page WAL writes --- 8943,8950 ---- * directory was not included in the base backup and the WAL archive was * cleared too before starting the backup. */ ! if (!duringrecovery) ! RequestXLogSwitch(); /* * Mark backup active in shared memory. We must do full-page WAL writes *************** *** 8943,8949 **** } else XLogCtl->Insert.nonExclusiveBackups++; ! XLogCtl->Insert.forcePageWrites = true; LWLockRelease(WALInsertLock); /* Ensure we release forcePageWrites if fail below */ --- 8978,8985 ---- } else XLogCtl->Insert.nonExclusiveBackups++; ! if (!duringrecovery) ! XLogCtl->Insert.forcePageWrites = true; LWLockRelease(WALInsertLock); /* Ensure we release forcePageWrites if fail below */ *************** *** 8994,9000 **** gotUniqueStartpoint = true; } LWLockRelease(WALInsertLock); ! } while (!gotUniqueStartpoint); XLByteToSeg(startpoint, _logId, _logSeg); XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg); --- 9030,9036 ---- gotUniqueStartpoint = true; } LWLockRelease(WALInsertLock); ! } while (!gotUniqueStartpoint && !duringrecovery); XLByteToSeg(startpoint, _logId, _logSeg); XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg); *************** *** 9087,9093 **** } if (!XLogCtl->Insert.exclusiveBackup && ! XLogCtl->Insert.nonExclusiveBackups == 0) { XLogCtl->Insert.forcePageWrites = false; } --- 9123,9130 ---- } if (!XLogCtl->Insert.exclusiveBackup && ! XLogCtl->Insert.nonExclusiveBackups == 0 && ! !RecoveryInProgress()) { XLogCtl->Insert.forcePageWrites = false; } *************** *** 9131,9136 **** --- 9168,9174 ---- do_pg_stop_backup(char *labelfile, bool waitforarchive) { bool exclusive = (labelfile == NULL); + bool duringrecovery = false; XLogRecPtr startpoint; XLogRecPtr stoppoint; XLogRecData rdata; *************** *** 9157,9168 **** (errmsg("must be superuser or replication role to run a backup")))); if (RecoveryInProgress()) ! ereport(ERROR, ! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), ! errmsg("recovery is in progress"), ! errhint("WAL control functions cannot be executed during recovery."))); ! if (!XLogIsNeeded()) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("WAL level not sufficient for making an online backup"), --- 9195,9203 ---- (errmsg("must be superuser or replication role to run a backup")))); if (RecoveryInProgress()) ! duringrecovery = true; ! if (!XLogIsNeeded() && !duringrecovery) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("WAL level not sufficient for making an online backup"), *************** *** 9187,9193 **** } if (!XLogCtl->Insert.exclusiveBackup && ! XLogCtl->Insert.nonExclusiveBackups == 0) { XLogCtl->Insert.forcePageWrites = false; } --- 9222,9229 ---- } if (!XLogCtl->Insert.exclusiveBackup && ! XLogCtl->Insert.nonExclusiveBackups == 0 && ! !duringrecovery) { XLogCtl->Insert.forcePageWrites = false; } *************** *** 9241,9246 **** --- 9277,9289 ---- } /* + * When pg_stop_backup is excuted on hot standby server, the result + * is minRecoveryPoint in the control file. + */ + if (duringrecovery) + return ControlFile->minRecoveryPoint; + + /* * Read and parse the START WAL LOCATION line (this code is pretty crude, * but we are not expecting any variability in the file format). */ *************** *** 9398,9404 **** XLogCtl->Insert.nonExclusiveBackups--; if (!XLogCtl->Insert.exclusiveBackup && ! XLogCtl->Insert.nonExclusiveBackups == 0) { XLogCtl->Insert.forcePageWrites = false; } --- 9441,9448 ---- XLogCtl->Insert.nonExclusiveBackups--; if (!XLogCtl->Insert.exclusiveBackup && ! XLogCtl->Insert.nonExclusiveBackups == 0 && ! !RecoveryInProgress()) { XLogCtl->Insert.forcePageWrites = false; } diff -rcN postgresql/src/backend/postmaster/postmaster.c postgresql_with_patch/src/backend/postmaster/postmaster.c *** postgresql/src/backend/postmaster/postmaster.c 2011-08-03 05:18:32.000000000 +0900 --- postgresql_with_patch/src/backend/postmaster/postmaster.c 2011-08-03 10:10:06.000000000 +0900 *************** *** 286,293 **** static PMState pmState = PM_INIT; - static bool ReachedNormalRunning = false; /* T if we've reached PM_RUN */ - bool ClientAuthInProgress = false; /* T during new-client * authentication */ --- 286,291 ---- *************** *** 2313,2319 **** * Startup succeeded, commence normal operations */ FatalError = false; - ReachedNormalRunning = true; pmState = PM_RUN; /* --- 2311,2316 ---- *************** *** 2853,2859 **** * backends to die off, but that doesn't work at present because * killing the startup process doesn't release its locks. */ ! if (CountChildren(BACKEND_TYPE_NORMAL) == 0) { if (StartupPID != 0) signal_child(StartupPID, SIGTERM); --- 2850,2856 ---- * backends to die off, but that doesn't work at present because * killing the startup process doesn't release its locks. */ ! if (CountChildren(BACKEND_TYPE_NORMAL) == 0 && !BackupInProgress()) { if (StartupPID != 0) signal_child(StartupPID, SIGTERM); *************** *** 3008,3022 **** { /* * Terminate backup mode to avoid recovery after a clean fast ! * shutdown. Since a backup can only be taken during normal ! * running (and not, for example, while running under Hot Standby) ! * it only makes sense to do this if we reached normal running. If ! * we're still in recovery, the backup file is one we're ! * recovering *from*, and we must keep it around so that recovery ! * restarts from the right place. */ ! if (ReachedNormalRunning) ! CancelBackup(); /* Normal exit from the postmaster is here */ ExitPostmaster(0); --- 3005,3013 ---- { /* * Terminate backup mode to avoid recovery after a clean fast ! * shutdown. */ ! CancelBackup(); /* Normal exit from the postmaster is here */ ExitPostmaster(0); *************** *** 4232,4237 **** --- 4223,4233 ---- (pmState == PM_STARTUP || pmState == PM_RECOVERY || pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY)) { + /* + * Terminate backup mode to avoid recovery after a clean promote. + */ + CancelBackup(); + /* Tell startup process to finish recovery */ signal_child(StartupPID, SIGUSR2); } diff -rcN postgresql/src/bin/pg_controldata/pg_controldata.c postgresql_with_patch/src/bin/pg_controldata/pg_controldata.c *** postgresql/src/bin/pg_controldata/pg_controldata.c 2011-08-03 05:18:32.000000000 +0900 --- postgresql_with_patch/src/bin/pg_controldata/pg_controldata.c 2011-08-03 10:10:06.000000000 +0900 *************** *** 86,91 **** --- 86,105 ---- return _("unrecognized wal_level"); } + static const char * + backupserver_str(BackupServer backupserver) + { + switch (backupserver) + { + case BACKUPSERVER_NONE: + return "none"; + case BACKUPSERVER_MASTER: + return "master"; + case BACKUPSERVER_SLAVE: + return "slave"; + } + return _("unrecognized backupserver"); + } int main(int argc, char *argv[]) *************** *** 232,237 **** --- 246,253 ---- printf(_("Backup start location: %X/%X\n"), ControlFile.backupStartPoint.xlogid, ControlFile.backupStartPoint.xrecoff); + printf(_("Backup from: %s\n"), + backupserver_str(ControlFile.backupserver)); printf(_("Current wal_level setting: %s\n"), wal_level_str(ControlFile.wal_level)); printf(_("Current max_connections setting: %d\n"), diff -rcN postgresql/src/bin/pg_ctl/pg_ctl.c postgresql_with_patch/src/bin/pg_ctl/pg_ctl.c *** postgresql/src/bin/pg_ctl/pg_ctl.c 2011-08-03 05:18:32.000000000 +0900 --- postgresql_with_patch/src/bin/pg_ctl/pg_ctl.c 2011-08-03 10:10:06.000000000 +0900 *************** *** 882,894 **** { /* * If backup_label exists, an online backup is running. Warn the user ! * that smart shutdown will wait for it to finish. However, if ! * recovery.conf is also present, we're recovering from an online ! * backup instead of performing one. */ if (shutdown_mode == SMART_MODE && ! stat(backup_file, &statbuf) == 0 && ! stat(recovery_file, &statbuf) != 0) { print_msg(_("WARNING: online backup mode is active\n" "Shutdown will not complete until pg_stop_backup() is called.\n\n")); --- 882,891 ---- { /* * If backup_label exists, an online backup is running. Warn the user ! * that smart shutdown will wait for it to finish. */ if (shutdown_mode == SMART_MODE && ! stat(backup_file, &statbuf) == 0) { print_msg(_("WARNING: online backup mode is active\n" "Shutdown will not complete until pg_stop_backup() is called.\n\n")); diff -rcN postgresql/src/include/access/xlog.h postgresql_with_patch/src/include/access/xlog.h *** postgresql/src/include/access/xlog.h 2011-08-03 05:18:32.000000000 +0900 --- postgresql_with_patch/src/include/access/xlog.h 2011-08-03 10:10:06.000000000 +0900 *************** *** 209,214 **** --- 209,222 ---- } WalLevel; extern int wal_level; + /* where to get backup */ + typedef enum BackupServer + { + BACKUPSERVER_NONE = 0, + BACKUPSERVER_MASTER, + BACKUPSERVER_SLAVE, + } BackupServer; + #define XLogArchivingActive() (XLogArchiveMode && wal_level >= WAL_LEVEL_ARCHIVE) #define XLogArchiveCommandSet() (XLogArchiveCommand[0] != '\0') diff -rcN postgresql/src/include/catalog/pg_control.h postgresql_with_patch/src/include/catalog/pg_control.h *** postgresql/src/include/catalog/pg_control.h 2011-08-03 05:18:32.000000000 +0900 --- postgresql_with_patch/src/include/catalog/pg_control.h 2011-08-03 10:10:06.000000000 +0900 *************** *** 142,147 **** --- 142,156 ---- XLogRecPtr backupStartPoint; /* + * backupserver is used while postgresql is in recovery mode to + * store the location of where the backup comes from. + * When Postgres starts recovery operations + * it is set to "none". During recovery it is updated to either "master", or "slave". + * When recovery operations finish it is updated back to "none". + */ + int backupserver; + + /* * Parameter settings that determine if the WAL can be used for archival * or hot standby. */