standby_online_backup_05.patch
application/octet-stream
Filename: standby_online_backup_05.patch
Type: application/octet-stream
Part: 0
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.
*/