Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
b387d16f
Commit
b387d16f
authored
Aug 04, 2004
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make use of backup label/history files to control recovery properly.
parent
cedd05ed
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
336 additions
and
89 deletions
+336
-89
src/backend/access/transam/xlog.c
src/backend/access/transam/xlog.c
+336
-89
No files found.
src/backend/access/transam/xlog.c
View file @
b387d16f
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.15
4 2004/08/03 20:32:3
2 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.15
5 2004/08/04 16:25:0
2 tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -146,6 +146,9 @@ static TransactionId recoveryStopXid;
...
@@ -146,6 +146,9 @@ static TransactionId recoveryStopXid;
static
time_t
recoveryStopTime
;
static
time_t
recoveryStopTime
;
static
bool
recoveryStopAfter
;
static
bool
recoveryStopAfter
;
/* constraint set by read_backup_label */
static
XLogRecPtr
recoveryMinXlogOffset
=
{
0
,
0
};
/*
/*
* During normal operation, the only timeline we care about is ThisTimeLineID.
* During normal operation, the only timeline we care about is ThisTimeLineID.
* During recovery, however, things are more complicated. To simplify life
* During recovery, however, things are more complicated. To simplify life
...
@@ -453,6 +456,8 @@ static void issue_xlog_fsync(void);
...
@@ -453,6 +456,8 @@ static void issue_xlog_fsync(void);
#ifdef WAL_DEBUG
#ifdef WAL_DEBUG
static
void
xlog_outrec
(
char
*
buf
,
XLogRecord
*
record
);
static
void
xlog_outrec
(
char
*
buf
,
XLogRecord
*
record
);
#endif
#endif
static
bool
read_backup_label
(
XLogRecPtr
*
checkPointLoc
);
static
void
remove_backup_label
(
void
);
/*
/*
...
@@ -1437,7 +1442,7 @@ XLogFlush(XLogRecPtr record)
...
@@ -1437,7 +1442,7 @@ XLogFlush(XLogRecPtr record)
* scenario has actually happened in the field several times with 7.1
* scenario has actually happened in the field several times with 7.1
* releases. Note that we cannot get here while InRedo is true, but if
* releases. Note that we cannot get here while InRedo is true, but if
* the bad page is brought in and marked dirty during recovery then
* the bad page is brought in and marked dirty during recovery then
* CreateCheck
p
oint will try to flush it at the end of recovery.)
* CreateCheck
P
oint will try to flush it at the end of recovery.)
*
*
* The current approach is to ERROR under normal conditions, but only
* The current approach is to ERROR under normal conditions, but only
* WARNING during recovery, so that the system can be brought up even
* WARNING during recovery, so that the system can be brought up even
...
@@ -4020,24 +4025,47 @@ StartupXLOG(void)
...
@@ -4020,24 +4025,47 @@ StartupXLOG(void)
recoveryTargetTLI
,
recoveryTargetTLI
,
ControlFile
->
checkPointCopy
.
ThisTimeLineID
)));
ControlFile
->
checkPointCopy
.
ThisTimeLineID
)));
if
(
read_backup_label
(
&
checkPointLoc
))
{
/*
* When a backup_label file is present, we want to roll forward from
* the checkpoint it identifies, rather than using pg_control.
*/
record
=
ReadCheckpointRecord
(
checkPointLoc
,
0
,
buffer
);
if
(
record
!=
NULL
)
{
ereport
(
LOG
,
(
errmsg
(
"checkpoint record is at %X/%X"
,
checkPointLoc
.
xlogid
,
checkPointLoc
.
xrecoff
)));
InRecovery
=
true
;
/* force recovery even if SHUTDOWNED */
}
else
{
ereport
(
PANIC
,
(
errmsg
(
"could not locate required checkpoint record"
),
errhint
(
"If you are not restoring from a backup, try removing $PGDATA/backup_label."
)));
}
}
else
{
/*
/*
* Get the last valid checkpoint record. If the latest one according
* Get the last valid checkpoint record. If the latest one according
* to pg_control is broken, try the next-to-last one.
* to pg_control is broken, try the next-to-last one.
*/
*/
record
=
ReadCheckpointRecord
(
ControlFile
->
checkPoint
,
1
,
buffer
);
checkPointLoc
=
ControlFile
->
checkPoint
;
record
=
ReadCheckpointRecord
(
checkPointLoc
,
1
,
buffer
);
if
(
record
!=
NULL
)
if
(
record
!=
NULL
)
{
{
checkPointLoc
=
ControlFile
->
checkPoint
;
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"checkpoint record is at %X/%X"
,
(
errmsg
(
"checkpoint record is at %X/%X"
,
checkPointLoc
.
xlogid
,
checkPointLoc
.
xrecoff
)));
checkPointLoc
.
xlogid
,
checkPointLoc
.
xrecoff
)));
}
}
else
else
{
{
record
=
ReadCheckpointRecord
(
ControlFile
->
prevCheckPoint
,
2
,
buffer
);
checkPointLoc
=
ControlFile
->
prevCheckPoint
;
record
=
ReadCheckpointRecord
(
checkPointLoc
,
2
,
buffer
);
if
(
record
!=
NULL
)
if
(
record
!=
NULL
)
{
{
checkPointLoc
=
ControlFile
->
prevCheckPoint
;
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"using previous checkpoint record at %X/%X"
,
(
errmsg
(
"using previous checkpoint record at %X/%X"
,
checkPointLoc
.
xlogid
,
checkPointLoc
.
xrecoff
)));
checkPointLoc
.
xlogid
,
checkPointLoc
.
xrecoff
)));
...
@@ -4047,6 +4075,8 @@ StartupXLOG(void)
...
@@ -4047,6 +4075,8 @@ StartupXLOG(void)
ereport
(
PANIC
,
ereport
(
PANIC
,
(
errmsg
(
"could not locate a valid checkpoint record"
)));
(
errmsg
(
"could not locate a valid checkpoint record"
)));
}
}
}
LastRec
=
RecPtr
=
checkPointLoc
;
LastRec
=
RecPtr
=
checkPointLoc
;
memcpy
(
&
checkPoint
,
XLogRecGetData
(
record
),
sizeof
(
CheckPoint
));
memcpy
(
&
checkPoint
,
XLogRecGetData
(
record
),
sizeof
(
CheckPoint
));
wasShutdown
=
(
record
->
xl_info
==
XLOG_CHECKPOINT_SHUTDOWN
);
wasShutdown
=
(
record
->
xl_info
==
XLOG_CHECKPOINT_SHUTDOWN
);
...
@@ -4097,25 +4127,24 @@ StartupXLOG(void)
...
@@ -4097,25 +4127,24 @@ StartupXLOG(void)
}
}
else
if
(
ControlFile
->
state
!=
DB_SHUTDOWNED
)
else
if
(
ControlFile
->
state
!=
DB_SHUTDOWNED
)
InRecovery
=
true
;
InRecovery
=
true
;
else
if
(
InArchiveRecovery
)
{
/* force recovery due to presence of recovery.conf */
InRecovery
=
true
;
}
/* REDO */
/* REDO */
if
(
InRecovery
||
InArchiveRecovery
)
if
(
InRecovery
)
{
{
int
rmid
;
int
rmid
;
if
(
InRecovery
)
if
(
InArchiveRecovery
)
{
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"database system was not properly shut down; "
(
errmsg
(
"automatic recovery in progress"
)));
"automatic recovery in progress"
)));
}
else
else
{
/* force recovery due to presence of recovery.conf */
InRecovery
=
true
;
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"
automatic recovery in progress"
)));
(
errmsg
(
"
database system was not properly shut down; "
}
"automatic recovery in progress"
)));
ControlFile
->
state
=
DB_IN_RECOVERY
;
ControlFile
->
state
=
DB_IN_RECOVERY
;
ControlFile
->
time
=
time
(
NULL
);
ControlFile
->
time
=
time
(
NULL
);
UpdateControlFile
();
UpdateControlFile
();
...
@@ -4228,6 +4257,20 @@ StartupXLOG(void)
...
@@ -4228,6 +4257,20 @@ StartupXLOG(void)
EndOfLog
=
EndRecPtr
;
EndOfLog
=
EndRecPtr
;
XLByteToPrevSeg
(
EndOfLog
,
endLogId
,
endLogSeg
);
XLByteToPrevSeg
(
EndOfLog
,
endLogId
,
endLogSeg
);
/*
* Complain if we did not roll forward far enough to render the backup
* dump consistent.
*/
if
(
XLByteLT
(
EndOfLog
,
recoveryMinXlogOffset
))
{
if
(
needNewTimeLine
)
/* stopped because of stop request */
ereport
(
FATAL
,
(
errmsg
(
"requested recovery stop point is before end time of backup dump"
)));
else
/* ran off end of WAL */
ereport
(
FATAL
,
(
errmsg
(
"WAL ends before end time of backup dump"
)));
}
/*
/*
* Consider whether we need to assign a new timeline ID.
* Consider whether we need to assign a new timeline ID.
*
*
...
@@ -4370,13 +4413,21 @@ StartupXLOG(void)
...
@@ -4370,13 +4413,21 @@ StartupXLOG(void)
* CreateCheckPoint operation; we don't want the broken primary
* CreateCheckPoint operation; we don't want the broken primary
* checkpoint to become prevCheckPoint...
* checkpoint to become prevCheckPoint...
*/
*/
if
(
XLByteEQ
(
checkPointLoc
,
ControlFile
->
prevCheckPoint
))
ControlFile
->
checkPoint
=
checkPointLoc
;
ControlFile
->
checkPoint
=
checkPointLoc
;
CreateCheckPoint
(
true
,
true
);
CreateCheckPoint
(
true
,
true
);
/*
/*
* Close down recovery environment
* Close down recovery environment
*/
*/
XLogCloseRelationCache
();
XLogCloseRelationCache
();
/*
* Now that we've checkpointed the recovery, it's safe to
* flush old backup_label, if present.
*/
remove_backup_label
();
}
}
/*
/*
...
@@ -4418,7 +4469,9 @@ StartupXLOG(void)
...
@@ -4418,7 +4469,9 @@ StartupXLOG(void)
/*
/*
* Subroutine to try to fetch and validate a prior checkpoint record.
* Subroutine to try to fetch and validate a prior checkpoint record.
* whichChkpt = 1 for "primary", 2 for "secondary", merely informative
*
* whichChkpt identifies the checkpoint (merely for reporting purposes).
* 1 for "primary", 2 for "secondary", 0 for "other" (backup_label)
*/
*/
static
XLogRecord
*
static
XLogRecord
*
ReadCheckpointRecord
(
XLogRecPtr
RecPtr
,
ReadCheckpointRecord
(
XLogRecPtr
RecPtr
,
...
@@ -4429,12 +4482,21 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
...
@@ -4429,12 +4482,21 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
if
(
!
XRecOffIsValid
(
RecPtr
.
xrecoff
))
if
(
!
XRecOffIsValid
(
RecPtr
.
xrecoff
))
{
{
if
(
whichChkpt
==
1
)
switch
(
whichChkpt
)
{
case
1
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid primary checkpoint link in control file"
)));
(
errmsg
(
"invalid primary checkpoint link in control file"
)));
else
break
;
case
2
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid secondary checkpoint link in control file"
)));
(
errmsg
(
"invalid secondary checkpoint link in control file"
)));
break
;
default:
ereport
(
LOG
,
(
errmsg
(
"invalid checkpoint link in backup_label file"
)));
break
;
}
return
NULL
;
return
NULL
;
}
}
...
@@ -4442,43 +4504,79 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
...
@@ -4442,43 +4504,79 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
if
(
record
==
NULL
)
if
(
record
==
NULL
)
{
{
if
(
whichChkpt
==
1
)
switch
(
whichChkpt
)
{
case
1
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid primary checkpoint record"
)));
(
errmsg
(
"invalid primary checkpoint record"
)));
else
break
;
case
2
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid secondary checkpoint record"
)));
(
errmsg
(
"invalid secondary checkpoint record"
)));
break
;
default:
ereport
(
LOG
,
(
errmsg
(
"invalid checkpoint record"
)));
break
;
}
return
NULL
;
return
NULL
;
}
}
if
(
record
->
xl_rmid
!=
RM_XLOG_ID
)
if
(
record
->
xl_rmid
!=
RM_XLOG_ID
)
{
{
if
(
whichChkpt
==
1
)
switch
(
whichChkpt
)
{
case
1
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid resource manager ID in primary checkpoint record"
)));
(
errmsg
(
"invalid resource manager ID in primary checkpoint record"
)));
else
break
;
case
2
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid resource manager ID in secondary checkpoint record"
)));
(
errmsg
(
"invalid resource manager ID in secondary checkpoint record"
)));
break
;
default:
ereport
(
LOG
,
(
errmsg
(
"invalid resource manager ID in checkpoint record"
)));
break
;
}
return
NULL
;
return
NULL
;
}
}
if
(
record
->
xl_info
!=
XLOG_CHECKPOINT_SHUTDOWN
&&
if
(
record
->
xl_info
!=
XLOG_CHECKPOINT_SHUTDOWN
&&
record
->
xl_info
!=
XLOG_CHECKPOINT_ONLINE
)
record
->
xl_info
!=
XLOG_CHECKPOINT_ONLINE
)
{
{
if
(
whichChkpt
==
1
)
switch
(
whichChkpt
)
{
case
1
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid xl_info in primary checkpoint record"
)));
(
errmsg
(
"invalid xl_info in primary checkpoint record"
)));
else
break
;
case
2
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid xl_info in secondary checkpoint record"
)));
(
errmsg
(
"invalid xl_info in secondary checkpoint record"
)));
break
;
default:
ereport
(
LOG
,
(
errmsg
(
"invalid xl_info in checkpoint record"
)));
break
;
}
return
NULL
;
return
NULL
;
}
}
if
(
record
->
xl_len
!=
sizeof
(
CheckPoint
))
if
(
record
->
xl_len
!=
sizeof
(
CheckPoint
))
{
{
if
(
whichChkpt
==
1
)
switch
(
whichChkpt
)
{
case
1
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid length of primary checkpoint record"
)));
(
errmsg
(
"invalid length of primary checkpoint record"
)));
else
break
;
case
2
:
ereport
(
LOG
,
ereport
(
LOG
,
(
errmsg
(
"invalid length of secondary checkpoint record"
)));
(
errmsg
(
"invalid length of secondary checkpoint record"
)));
break
;
default:
ereport
(
LOG
,
(
errmsg
(
"invalid length of checkpoint record"
)));
break
;
}
return
NULL
;
return
NULL
;
}
}
return
record
;
return
record
;
...
@@ -5065,10 +5163,11 @@ pg_start_backup(PG_FUNCTION_ARGS)
...
@@ -5065,10 +5163,11 @@ pg_start_backup(PG_FUNCTION_ARGS)
text
*
backupid
=
PG_GETARG_TEXT_P
(
0
);
text
*
backupid
=
PG_GETARG_TEXT_P
(
0
);
text
*
result
;
text
*
result
;
char
*
backupidstr
;
char
*
backupidstr
;
XLogRecPtr
checkpointloc
;
XLogRecPtr
startpoint
;
XLogRecPtr
startpoint
;
time_t
stamp_time
;
time_t
stamp_time
;
char
strfbuf
[
128
];
char
strfbuf
[
128
];
char
labelfile
name
[
MAXPGPATH
];
char
labelfile
path
[
MAXPGPATH
];
char
xlogfilename
[
MAXFNAMELEN
];
char
xlogfilename
[
MAXFNAMELEN
];
uint32
_logId
;
uint32
_logId
;
uint32
_logSeg
;
uint32
_logSeg
;
...
@@ -5082,10 +5181,23 @@ pg_start_backup(PG_FUNCTION_ARGS)
...
@@ -5082,10 +5181,23 @@ pg_start_backup(PG_FUNCTION_ARGS)
backupidstr
=
DatumGetCString
(
DirectFunctionCall1
(
textout
,
backupidstr
=
DatumGetCString
(
DirectFunctionCall1
(
textout
,
PointerGetDatum
(
backupid
)));
PointerGetDatum
(
backupid
)));
/*
/*
* The oldest point in WAL that would be needed to restore starting from
* Force a CHECKPOINT. This is not strictly necessary, but it seems
* the most recent checkpoint is precisely the RedoRecPtr.
* like a good idea to minimize the amount of past WAL needed to use the
* backup. Also, this guarantees that two successive backup runs
* will have different checkpoint positions and hence different history
* file names, even if nothing happened in between.
*/
RequestCheckpoint
(
true
);
/*
* Now we need to fetch the checkpoint record location, and also its
* REDO pointer. The oldest point in WAL that would be needed to restore
* starting from the checkpoint is precisely the REDO pointer.
*/
*/
startpoint
=
GetRedoRecPtr
();
LWLockAcquire
(
ControlFileLock
,
LW_EXCLUSIVE
);
checkpointloc
=
ControlFile
->
checkPoint
;
startpoint
=
ControlFile
->
checkPointCopy
.
redo
;
LWLockRelease
(
ControlFileLock
);
XLByteToSeg
(
startpoint
,
_logId
,
_logSeg
);
XLByteToSeg
(
startpoint
,
_logId
,
_logSeg
);
XLogFileName
(
xlogfilename
,
ThisTimeLineID
,
_logId
,
_logSeg
);
XLogFileName
(
xlogfilename
,
ThisTimeLineID
,
_logId
,
_logSeg
);
/*
/*
...
@@ -5101,39 +5213,41 @@ pg_start_backup(PG_FUNCTION_ARGS)
...
@@ -5101,39 +5213,41 @@ pg_start_backup(PG_FUNCTION_ARGS)
/*
/*
* Check for existing backup label --- implies a backup is already running
* Check for existing backup label --- implies a backup is already running
*/
*/
snprintf
(
labelfile
name
,
MAXPGPATH
,
"%s/backup_label"
,
DataDir
);
snprintf
(
labelfile
path
,
MAXPGPATH
,
"%s/backup_label"
,
DataDir
);
if
(
stat
(
labelfile
name
,
&
stat_buf
)
!=
0
)
if
(
stat
(
labelfile
path
,
&
stat_buf
)
!=
0
)
{
{
if
(
errno
!=
ENOENT
)
if
(
errno
!=
ENOENT
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode_for_file_access
(),
(
errcode_for_file_access
(),
errmsg
(
"could not stat
\"
%s
\"
: %m"
,
errmsg
(
"could not stat
\"
%s
\"
: %m"
,
labelfile
name
)));
labelfile
path
)));
}
}
else
else
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
errmsg
(
"a backup is already in progress"
),
errmsg
(
"a backup is already in progress"
),
errhint
(
"If you're sure there is no backup in progress, remove file
\"
%s
\"
and try again."
,
errhint
(
"If you're sure there is no backup in progress, remove file
\"
%s
\"
and try again."
,
labelfile
name
)));
labelfile
path
)));
/*
/*
* Okay, write the file
* Okay, write the file
*/
*/
fp
=
AllocateFile
(
labelfile
name
,
"w"
);
fp
=
AllocateFile
(
labelfile
path
,
"w"
);
if
(
!
fp
)
if
(
!
fp
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode_for_file_access
(),
(
errcode_for_file_access
(),
errmsg
(
"could not create file
\"
%s
\"
: %m"
,
errmsg
(
"could not create file
\"
%s
\"
: %m"
,
labelfile
name
)));
labelfile
path
)));
fprintf
(
fp
,
"START WAL LOCATION: %X/%X (file %s)
\n
"
,
fprintf
(
fp
,
"START WAL LOCATION: %X/%X (file %s)
\n
"
,
startpoint
.
xlogid
,
startpoint
.
xrecoff
,
xlogfilename
);
startpoint
.
xlogid
,
startpoint
.
xrecoff
,
xlogfilename
);
fprintf
(
fp
,
"CHECKPOINT LOCATION: %X/%X
\n
"
,
checkpointloc
.
xlogid
,
checkpointloc
.
xrecoff
);
fprintf
(
fp
,
"START TIME: %s
\n
"
,
strfbuf
);
fprintf
(
fp
,
"START TIME: %s
\n
"
,
strfbuf
);
fprintf
(
fp
,
"LABEL: %s
\n
"
,
backupidstr
);
fprintf
(
fp
,
"LABEL: %s
\n
"
,
backupidstr
);
if
(
fflush
(
fp
)
||
ferror
(
fp
)
||
FreeFile
(
fp
))
if
(
fflush
(
fp
)
||
ferror
(
fp
)
||
FreeFile
(
fp
))
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode_for_file_access
(),
(
errcode_for_file_access
(),
errmsg
(
"could not write file
\"
%s
\"
: %m"
,
errmsg
(
"could not write file
\"
%s
\"
: %m"
,
labelfile
name
)));
labelfile
path
)));
/*
/*
* We're done. As a convenience, return the starting WAL offset.
* We're done. As a convenience, return the starting WAL offset.
*/
*/
...
@@ -5161,8 +5275,8 @@ pg_stop_backup(PG_FUNCTION_ARGS)
...
@@ -5161,8 +5275,8 @@ pg_stop_backup(PG_FUNCTION_ARGS)
XLogRecPtr
stoppoint
;
XLogRecPtr
stoppoint
;
time_t
stamp_time
;
time_t
stamp_time
;
char
strfbuf
[
128
];
char
strfbuf
[
128
];
char
labelfile
name
[
MAXPGPATH
];
char
labelfile
path
[
MAXPGPATH
];
char
histfile
name
[
MAXPGPATH
];
char
histfile
path
[
MAXPGPATH
];
char
startxlogfilename
[
MAXFNAMELEN
];
char
startxlogfilename
[
MAXFNAMELEN
];
char
stopxlogfilename
[
MAXFNAMELEN
];
char
stopxlogfilename
[
MAXFNAMELEN
];
uint32
_logId
;
uint32
_logId
;
...
@@ -5199,15 +5313,15 @@ pg_stop_backup(PG_FUNCTION_ARGS)
...
@@ -5199,15 +5313,15 @@ pg_stop_backup(PG_FUNCTION_ARGS)
/*
/*
* Open the existing label file
* Open the existing label file
*/
*/
snprintf
(
labelfile
name
,
MAXPGPATH
,
"%s/backup_label"
,
DataDir
);
snprintf
(
labelfile
path
,
MAXPGPATH
,
"%s/backup_label"
,
DataDir
);
lfp
=
AllocateFile
(
labelfile
name
,
"r"
);
lfp
=
AllocateFile
(
labelfile
path
,
"r"
);
if
(
!
lfp
)
if
(
!
lfp
)
{
{
if
(
errno
!=
ENOENT
)
if
(
errno
!=
ENOENT
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode_for_file_access
(),
(
errcode_for_file_access
(),
errmsg
(
"could not read file
\"
%s
\"
: %m"
,
errmsg
(
"could not read file
\"
%s
\"
: %m"
,
labelfile
name
)));
labelfile
path
)));
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
errmsg
(
"a backup is not in progress"
)));
errmsg
(
"a backup is not in progress"
)));
...
@@ -5221,24 +5335,24 @@ pg_stop_backup(PG_FUNCTION_ARGS)
...
@@ -5221,24 +5335,24 @@ pg_stop_backup(PG_FUNCTION_ARGS)
&
ch
)
!=
4
||
ch
!=
'\n'
)
&
ch
)
!=
4
||
ch
!=
'\n'
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
errmsg
(
"invalid data in file
\"
%s
\"
"
,
labelfile
name
)));
errmsg
(
"invalid data in file
\"
%s
\"
"
,
labelfile
path
)));
/*
/*
* Write the backup history file
* Write the backup history file
*/
*/
XLByteToSeg
(
startpoint
,
_logId
,
_logSeg
);
XLByteToSeg
(
startpoint
,
_logId
,
_logSeg
);
BackupHistoryFilePath
(
histfile
name
,
ThisTimeLineID
,
_logId
,
_logSeg
,
BackupHistoryFilePath
(
histfile
path
,
ThisTimeLineID
,
_logId
,
_logSeg
,
startpoint
.
xrecoff
%
XLogSegSize
);
startpoint
.
xrecoff
%
XLogSegSize
);
fp
=
AllocateFile
(
histfile
name
,
"w"
);
fp
=
AllocateFile
(
histfile
path
,
"w"
);
if
(
!
fp
)
if
(
!
fp
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode_for_file_access
(),
(
errcode_for_file_access
(),
errmsg
(
"could not create file
\"
%s
\"
: %m"
,
errmsg
(
"could not create file
\"
%s
\"
: %m"
,
histfile
name
)));
histfile
path
)));
fprintf
(
fp
,
"START WAL LOCATION: %X/%X (file %s)
\n
"
,
fprintf
(
fp
,
"START WAL LOCATION: %X/%X (file %s)
\n
"
,
startpoint
.
xlogid
,
startpoint
.
xrecoff
,
startxlogfilename
);
startpoint
.
xlogid
,
startpoint
.
xrecoff
,
startxlogfilename
);
fprintf
(
fp
,
"STOP WAL LOCATION: %X/%X (file %s)
\n
"
,
fprintf
(
fp
,
"STOP WAL LOCATION: %X/%X (file %s)
\n
"
,
stoppoint
.
xlogid
,
stoppoint
.
xrecoff
,
stopxlogfilename
);
stoppoint
.
xlogid
,
stoppoint
.
xrecoff
,
stopxlogfilename
);
/* transfer
start time and label
lines from label to history file */
/* transfer
remaining
lines from label to history file */
while
((
ich
=
fgetc
(
lfp
))
!=
EOF
)
while
((
ich
=
fgetc
(
lfp
))
!=
EOF
)
fputc
(
ich
,
fp
);
fputc
(
ich
,
fp
);
fprintf
(
fp
,
"STOP TIME: %s
\n
"
,
strfbuf
);
fprintf
(
fp
,
"STOP TIME: %s
\n
"
,
strfbuf
);
...
@@ -5246,7 +5360,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
...
@@ -5246,7 +5360,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode_for_file_access
(),
(
errcode_for_file_access
(),
errmsg
(
"could not write file
\"
%s
\"
: %m"
,
errmsg
(
"could not write file
\"
%s
\"
: %m"
,
histfile
name
)));
histfile
path
)));
/*
/*
* Close and remove the backup label file
* Close and remove the backup label file
*/
*/
...
@@ -5254,20 +5368,20 @@ pg_stop_backup(PG_FUNCTION_ARGS)
...
@@ -5254,20 +5368,20 @@ pg_stop_backup(PG_FUNCTION_ARGS)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode_for_file_access
(),
(
errcode_for_file_access
(),
errmsg
(
"could not read file
\"
%s
\"
: %m"
,
errmsg
(
"could not read file
\"
%s
\"
: %m"
,
labelfile
name
)));
labelfile
path
)));
if
(
unlink
(
labelfile
name
)
!=
0
)
if
(
unlink
(
labelfile
path
)
!=
0
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode_for_file_access
(),
(
errcode_for_file_access
(),
errmsg
(
"could not remove file
\"
%s
\"
: %m"
,
errmsg
(
"could not remove file
\"
%s
\"
: %m"
,
labelfile
name
)));
labelfile
path
)));
/*
/*
* Notify archiver that history file may be archived immediately
* Notify archiver that history file may be archived immediately
*/
*/
if
(
XLogArchivingActive
())
if
(
XLogArchivingActive
())
{
{
BackupHistoryFileName
(
histfile
name
,
ThisTimeLineID
,
_logId
,
_logSeg
,
BackupHistoryFileName
(
histfile
path
,
ThisTimeLineID
,
_logId
,
_logSeg
,
startpoint
.
xrecoff
%
XLogSegSize
);
startpoint
.
xrecoff
%
XLogSegSize
);
XLogArchiveNotify
(
histfile
name
);
XLogArchiveNotify
(
histfile
path
);
}
}
/*
/*
* We're done. As a convenience, return the ending WAL offset.
* We're done. As a convenience, return the ending WAL offset.
...
@@ -5278,3 +5392,136 @@ pg_stop_backup(PG_FUNCTION_ARGS)
...
@@ -5278,3 +5392,136 @@ pg_stop_backup(PG_FUNCTION_ARGS)
CStringGetDatum
(
stopxlogfilename
)));
CStringGetDatum
(
stopxlogfilename
)));
PG_RETURN_TEXT_P
(
result
);
PG_RETURN_TEXT_P
(
result
);
}
}
/*
* read_backup_label: check to see if a backup_label file is present
*
* If we see a backup_label during recovery, we assume that we are recovering
* from a backup dump file, and we therefore roll forward from the checkpoint
* identified by the label file, NOT what pg_control says. This avoids the
* problem that pg_control might have been archived one or more checkpoints
* later than the start of the dump, and so if we rely on it as the start
* point, we will fail to restore a consistent database state.
*
* We also attempt to retrieve the corresponding backup history file.
* If successful, set recoveryMinXlogOffset to constrain valid PITR stopping
* points.
*
* Returns TRUE if a backup_label was found (and fills the checkpoint
* location into *checkPointLoc); returns FALSE if not.
*/
static
bool
read_backup_label
(
XLogRecPtr
*
checkPointLoc
)
{
XLogRecPtr
startpoint
;
XLogRecPtr
stoppoint
;
char
labelfilepath
[
MAXPGPATH
];
char
histfilename
[
MAXFNAMELEN
];
char
histfilepath
[
MAXPGPATH
];
char
startxlogfilename
[
MAXFNAMELEN
];
char
stopxlogfilename
[
MAXFNAMELEN
];
TimeLineID
tli
;
uint32
_logId
;
uint32
_logSeg
;
FILE
*
lfp
;
FILE
*
fp
;
char
ch
;
/*
* See if label file is present
*/
snprintf
(
labelfilepath
,
MAXPGPATH
,
"%s/backup_label"
,
DataDir
);
lfp
=
AllocateFile
(
labelfilepath
,
"r"
);
if
(
!
lfp
)
{
if
(
errno
!=
ENOENT
)
ereport
(
FATAL
,
(
errcode_for_file_access
(),
errmsg
(
"could not read file
\"
%s
\"
: %m"
,
labelfilepath
)));
return
false
;
/* it's not there, all is fine */
}
/*
* Read and parse the START WAL LOCATION and CHECKPOINT lines (this code
* is pretty crude, but we are not expecting any variability in the file
* format).
*/
if
(
fscanf
(
lfp
,
"START WAL LOCATION: %X/%X (file %08X%16s)%c"
,
&
startpoint
.
xlogid
,
&
startpoint
.
xrecoff
,
&
tli
,
startxlogfilename
,
&
ch
)
!=
5
||
ch
!=
'\n'
)
ereport
(
FATAL
,
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
errmsg
(
"invalid data in file
\"
%s
\"
"
,
labelfilepath
)));
if
(
fscanf
(
lfp
,
"CHECKPOINT LOCATION: %X/%X%c"
,
&
checkPointLoc
->
xlogid
,
&
checkPointLoc
->
xrecoff
,
&
ch
)
!=
3
||
ch
!=
'\n'
)
ereport
(
FATAL
,
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
errmsg
(
"invalid data in file
\"
%s
\"
"
,
labelfilepath
)));
if
(
ferror
(
lfp
)
||
FreeFile
(
lfp
))
ereport
(
FATAL
,
(
errcode_for_file_access
(),
errmsg
(
"could not read file
\"
%s
\"
: %m"
,
labelfilepath
)));
/*
* Try to retrieve the backup history file (no error if we can't)
*/
XLByteToSeg
(
startpoint
,
_logId
,
_logSeg
);
BackupHistoryFileName
(
histfilename
,
tli
,
_logId
,
_logSeg
,
startpoint
.
xrecoff
%
XLogSegSize
);
if
(
InArchiveRecovery
)
RestoreArchivedFile
(
histfilepath
,
histfilename
,
"RECOVERYHISTORY"
,
0
);
else
BackupHistoryFilePath
(
histfilepath
,
tli
,
_logId
,
_logSeg
,
startpoint
.
xrecoff
%
XLogSegSize
);
fp
=
AllocateFile
(
histfilepath
,
"r"
);
if
(
fp
)
{
/*
* Parse history file to identify stop point.
*/
if
(
fscanf
(
fp
,
"START WAL LOCATION: %X/%X (file %24s)%c"
,
&
startpoint
.
xlogid
,
&
startpoint
.
xrecoff
,
startxlogfilename
,
&
ch
)
!=
4
||
ch
!=
'\n'
)
ereport
(
FATAL
,
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
errmsg
(
"invalid data in file
\"
%s
\"
"
,
histfilename
)));
if
(
fscanf
(
fp
,
"STOP WAL LOCATION: %X/%X (file %24s)%c"
,
&
stoppoint
.
xlogid
,
&
stoppoint
.
xrecoff
,
stopxlogfilename
,
&
ch
)
!=
4
||
ch
!=
'\n'
)
ereport
(
FATAL
,
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
errmsg
(
"invalid data in file
\"
%s
\"
"
,
histfilename
)));
recoveryMinXlogOffset
=
stoppoint
;
if
(
ferror
(
fp
)
||
FreeFile
(
fp
))
ereport
(
FATAL
,
(
errcode_for_file_access
(),
errmsg
(
"could not read file
\"
%s
\"
: %m"
,
histfilepath
)));
}
return
true
;
}
/*
* remove_backup_label: remove any extant backup_label after successful
* recovery. Once we have completed the end-of-recovery checkpoint there
* is no reason to have to replay from the start point indicated by the
* label (and indeed we'll probably have removed/recycled the needed WAL
* segments), so remove the label to prevent trouble in later crash recoveries.
*/
static
void
remove_backup_label
(
void
)
{
char
labelfilepath
[
MAXPGPATH
];
snprintf
(
labelfilepath
,
MAXPGPATH
,
"%s/backup_label"
,
DataDir
);
if
(
unlink
(
labelfilepath
)
!=
0
)
if
(
errno
!=
ENOENT
)
ereport
(
FATAL
,
(
errcode_for_file_access
(),
errmsg
(
"could not remove file
\"
%s
\"
: %m"
,
labelfilepath
)));
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment