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-06-30 10:04:48.000000000 +0900 --- postgresql_with_patch/src/backend/access/transam/xlog.c 2011-07-11 18:46:45.000000000 +0900 *************** *** 6284,6289 **** --- 6284,6303 ---- /* 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 *************** *** 6592,6597 **** --- 6606,6631 ---- /* 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. *************** *** 8512,8517 **** --- 8546,8552 ---- if (XLByteLT(ControlFile->minRecoveryPoint, lsn)) ControlFile->minRecoveryPoint = lsn; MemSet(&ControlFile->backupStartPoint, 0, sizeof(XLogRecPtr)); + ControlFile->backupserver = BACKUPSERVER_NONE; UpdateControlFile(); LWLockRelease(ControlFileLock); *************** *** 8845,8850 **** --- 8880,8886 ---- 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; *************** *** 8862,8871 **** 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, --- 8898,8904 ---- errmsg("must be superuser or replication role to run a backup"))); if (RecoveryInProgress()) ! duringrecovery = true; if (!XLogIsNeeded()) ereport(ERROR, *************** *** 8890,8896 **** * 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 --- 8923,8930 ---- * 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 *************** *** 8924,8930 **** } else XLogCtl->Insert.nonExclusiveBackups++; ! XLogCtl->Insert.forcePageWrites = true; LWLockRelease(WALInsertLock); /* Ensure we release forcePageWrites if fail below */ --- 8958,8965 ---- } else XLogCtl->Insert.nonExclusiveBackups++; ! if (!duringrecovery) ! XLogCtl->Insert.forcePageWrites = true; LWLockRelease(WALInsertLock); /* Ensure we release forcePageWrites if fail below */ *************** *** 9112,9117 **** --- 9147,9153 ---- do_pg_stop_backup(char *labelfile, bool waitforarchive) { bool exclusive = (labelfile == NULL); + bool duringrecovery = false; XLogRecPtr startpoint; XLogRecPtr stoppoint; XLogRecData rdata; *************** *** 9138,9147 **** (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, --- 9174,9180 ---- (errmsg("must be superuser or replication role to run a backup")))); if (RecoveryInProgress()) ! duringrecovery = true; if (!XLogIsNeeded()) ereport(ERROR, *************** *** 9168,9174 **** } if (!XLogCtl->Insert.exclusiveBackup && ! XLogCtl->Insert.nonExclusiveBackups == 0) { XLogCtl->Insert.forcePageWrites = false; } --- 9201,9208 ---- } if (!XLogCtl->Insert.exclusiveBackup && ! XLogCtl->Insert.nonExclusiveBackups == 0 && ! !duringrecovery) { XLogCtl->Insert.forcePageWrites = false; } *************** *** 9222,9227 **** --- 9256,9268 ---- } /* + * 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). */ 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-06-30 10:04:48.000000000 +0900 --- postgresql_with_patch/src/bin/pg_controldata/pg_controldata.c 2011-07-07 18:23:22.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/include/access/xlog.h postgresql_with_patch/src/include/access/xlog.h *** postgresql/src/include/access/xlog.h 2011-06-30 10:04:48.000000000 +0900 --- postgresql_with_patch/src/include/access/xlog.h 2011-07-07 15:32:57.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-06-30 10:04:48.000000000 +0900 --- postgresql_with_patch/src/include/catalog/pg_control.h 2011-07-11 14:34:09.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. */