You've already forked pg_probackup
mirror of
https://github.com/postgrespro/pg_probackup.git
synced 2025-07-16 07:14:15 +02:00
Support multiple versions of postgres servers with one pg_rman binary.
git-svn-id: http://pg-rman.googlecode.com/svn/trunk@16 182aca00-e38e-11de-a668-6fd11605f5ce
This commit is contained in:
34
backup.c
34
backup.c
@ -33,7 +33,6 @@ static void backup_files(const char *from_root, const char *to_root,
|
|||||||
static parray *do_backup_database(parray *backup_list, bool smooth_checkpoint);
|
static parray *do_backup_database(parray *backup_list, bool smooth_checkpoint);
|
||||||
static parray *do_backup_arclog(parray *backup_list);
|
static parray *do_backup_arclog(parray *backup_list);
|
||||||
static parray *do_backup_srvlog(parray *backup_list);
|
static parray *do_backup_srvlog(parray *backup_list);
|
||||||
static void confirm_compatibility(void);
|
|
||||||
static void confirm_block_size(const char *name, int blcksz);
|
static void confirm_block_size(const char *name, int blcksz);
|
||||||
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup);
|
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup);
|
||||||
static void pg_stop_backup(pgBackup *backup);
|
static void pg_stop_backup(pgBackup *backup);
|
||||||
@ -463,7 +462,7 @@ do_backup(bool smooth_checkpoint,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* confirm data block size and xlog block size are compatible */
|
/* confirm data block size and xlog block size are compatible */
|
||||||
confirm_compatibility();
|
(void) get_server_version();
|
||||||
|
|
||||||
/* setup cleanup callback function */
|
/* setup cleanup callback function */
|
||||||
in_backup = true;
|
in_backup = true;
|
||||||
@ -585,27 +584,38 @@ do_backup(bool smooth_checkpoint,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is the server compatible with this program?
|
* get server version and confirm block sizes.
|
||||||
*/
|
*/
|
||||||
static void
|
int
|
||||||
confirm_compatibility(void)
|
get_server_version(void)
|
||||||
{
|
{
|
||||||
int server_version;
|
static int server_version = 0;
|
||||||
|
bool my_conn;
|
||||||
|
|
||||||
|
/* return cached server version */
|
||||||
|
if (server_version > 0)
|
||||||
|
return server_version;
|
||||||
|
|
||||||
|
my_conn = (connection == NULL);
|
||||||
|
|
||||||
|
if (my_conn)
|
||||||
reconnect();
|
reconnect();
|
||||||
|
|
||||||
/* confirm server version */
|
/* confirm server version */
|
||||||
server_version = PQserverVersion(connection);
|
server_version = PQserverVersion(connection);
|
||||||
if (server_version / 100 != PG_VERSION_NUM / 100)
|
if (server_version < 80000)
|
||||||
elog(ERROR_PG_INCOMPATIBLE,
|
elog(ERROR_PG_INCOMPATIBLE,
|
||||||
_("version mismatch. server is %d and %s is %d."),
|
_("server version is %d, but must be 8.0 or higher."),
|
||||||
server_version, PROGRAM_NAME, PG_VERSION_NUM);
|
server_version);
|
||||||
|
|
||||||
/* confirm block_size (BLCKSZ) and wal_block_size (XLOG_BLCKSZ) */
|
/* confirm block_size (BLCKSZ) and wal_block_size (XLOG_BLCKSZ) */
|
||||||
confirm_block_size("block_size", BLCKSZ);
|
confirm_block_size("block_size", BLCKSZ);
|
||||||
confirm_block_size("wal_block_size", XLOG_BLCKSZ);
|
confirm_block_size("wal_block_size", XLOG_BLCKSZ);
|
||||||
|
|
||||||
|
if (my_conn)
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
|
return server_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -637,11 +647,13 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
|
|||||||
{
|
{
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
const char *params[2];
|
const char *params[2];
|
||||||
|
int server_version;
|
||||||
|
|
||||||
params[0] = label;
|
params[0] = label;
|
||||||
|
|
||||||
reconnect();
|
reconnect();
|
||||||
if (PQserverVersion(connection) >= 80400)
|
server_version = get_server_version();
|
||||||
|
if (server_version >= 80400)
|
||||||
{
|
{
|
||||||
params[1] = smooth ? "false" : "true";
|
params[1] = smooth ? "false" : "true";
|
||||||
res = execute("SELECT * from pg_xlogfile_name_offset(pg_start_backup($1, $2))", 2, params);
|
res = execute("SELECT * from pg_xlogfile_name_offset(pg_start_backup($1, $2))", 2, params);
|
||||||
@ -649,7 +661,7 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* v8.3 always uses smooth checkpoint */
|
/* v8.3 always uses smooth checkpoint */
|
||||||
if (!smooth && PQserverVersion(connection) >= 80300)
|
if (!smooth && server_version >= 80300)
|
||||||
command("CHECKPOINT", 0, NULL);
|
command("CHECKPOINT", 0, NULL);
|
||||||
res = execute("SELECT * from pg_xlogfile_name_offset(pg_start_backup($1))", 1, params);
|
res = execute("SELECT * from pg_xlogfile_name_offset(pg_start_backup($1))", 1, params);
|
||||||
}
|
}
|
||||||
|
122
data.c
122
data.c
@ -152,9 +152,53 @@ doInflate(z_stream *zp, size_t in_size, size_t out_size,void *inbuf,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define PG_PAGE_LAYOUT_VERSION_v80 2 /* 8.0 */
|
||||||
|
#define PG_PAGE_LAYOUT_VERSION_v81 3 /* 8.1 - 8.2 */
|
||||||
|
#define PG_PAGE_LAYOUT_VERSION_v83 4 /* 8.3 - */
|
||||||
|
|
||||||
|
/* 80000 <= PG_VERSION_NUM < 80300 */
|
||||||
|
typedef struct PageHeaderData_v80
|
||||||
|
{
|
||||||
|
XLogRecPtr pd_lsn;
|
||||||
|
TimeLineID pd_tli;
|
||||||
|
LocationIndex pd_lower;
|
||||||
|
LocationIndex pd_upper;
|
||||||
|
LocationIndex pd_special;
|
||||||
|
uint16 pd_pagesize_version;
|
||||||
|
ItemIdData pd_linp[1];
|
||||||
|
} PageHeaderData_v80;
|
||||||
|
|
||||||
|
#define PageGetPageSize_v80(page) \
|
||||||
|
((Size) ((page)->pd_pagesize_version & (uint16) 0xFF00))
|
||||||
|
#define PageGetPageLayoutVersion_v80(page) \
|
||||||
|
((page)->pd_pagesize_version & 0x00FF)
|
||||||
|
#define SizeOfPageHeaderData_v80 (offsetof(PageHeaderData_v80, pd_linp))
|
||||||
|
|
||||||
|
/* 80300 <= PG_VERSION_NUM */
|
||||||
|
typedef struct PageHeaderData_v83
|
||||||
|
{
|
||||||
|
XLogRecPtr pd_lsn;
|
||||||
|
uint16 pd_tli;
|
||||||
|
uint16 pd_flags;
|
||||||
|
LocationIndex pd_lower;
|
||||||
|
LocationIndex pd_upper;
|
||||||
|
LocationIndex pd_special;
|
||||||
|
uint16 pd_pagesize_version;
|
||||||
|
TransactionId pd_prune_xid;
|
||||||
|
ItemIdData pd_linp[1];
|
||||||
|
} PageHeaderData_v83;
|
||||||
|
|
||||||
|
#define PageGetPageSize_v83(page) \
|
||||||
|
((Size) ((page)->pd_pagesize_version & (uint16) 0xFF00))
|
||||||
|
#define PageGetPageLayoutVersion_v83(page) \
|
||||||
|
((page)->pd_pagesize_version & 0x00FF)
|
||||||
|
#define SizeOfPageHeaderData_v83 (offsetof(PageHeaderData_v83, pd_linp))
|
||||||
|
#define PD_VALID_FLAG_BITS_v83 0x0007
|
||||||
|
|
||||||
typedef union DataPage
|
typedef union DataPage
|
||||||
{
|
{
|
||||||
PageHeaderData header;
|
PageHeaderData_v80 v80; /* 8.0 - 8.2 */
|
||||||
|
PageHeaderData_v83 v83; /* 8.3 - */
|
||||||
char data[BLCKSZ];
|
char data[BLCKSZ];
|
||||||
} DataPage;
|
} DataPage;
|
||||||
|
|
||||||
@ -166,32 +210,51 @@ typedef struct BackupPageHeader
|
|||||||
} BackupPageHeader;
|
} BackupPageHeader;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
is_valid_header(const PageHeader page)
|
parse_page(const DataPage *page, int server_version,
|
||||||
|
XLogRecPtr *lsn, uint16 *offset, uint16 *length)
|
||||||
{
|
{
|
||||||
const char *pagebytes;
|
uint16 page_layout_version;
|
||||||
int i;
|
|
||||||
|
/* Determine page layout version */
|
||||||
|
if (server_version < 80100)
|
||||||
|
page_layout_version = PG_PAGE_LAYOUT_VERSION_v80;
|
||||||
|
else if (server_version < 80300)
|
||||||
|
page_layout_version = PG_PAGE_LAYOUT_VERSION_v81;
|
||||||
|
else
|
||||||
|
page_layout_version = PG_PAGE_LAYOUT_VERSION_v83;
|
||||||
|
|
||||||
/* Check normal case */
|
/* Check normal case */
|
||||||
if (PageGetPageSize(page) == BLCKSZ &&
|
if (server_version < 80300)
|
||||||
PageGetPageLayoutVersion(page) == PG_PAGE_LAYOUT_VERSION &&
|
|
||||||
#if PG_VERSION_NUM >= 80300
|
|
||||||
(page->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
|
|
||||||
#endif
|
|
||||||
page->pd_lower >= SizeOfPageHeaderData &&
|
|
||||||
page->pd_lower <= page->pd_upper &&
|
|
||||||
page->pd_upper <= page->pd_special &&
|
|
||||||
page->pd_special <= BLCKSZ &&
|
|
||||||
page->pd_special == MAXALIGN(page->pd_special))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* Check all-zeroes case */
|
|
||||||
pagebytes = (char *) page;
|
|
||||||
for (i = 0; i < BLCKSZ; i++)
|
|
||||||
{
|
{
|
||||||
if (pagebytes[i] != 0)
|
const PageHeaderData_v80 *v80 = &page->v80;
|
||||||
return false;
|
|
||||||
}
|
if (PageGetPageSize_v80(v80) == BLCKSZ &&
|
||||||
|
PageGetPageLayoutVersion_v80(v80) == page_layout_version &&
|
||||||
|
v80->pd_lower >= SizeOfPageHeaderData_v80 &&
|
||||||
|
v80->pd_lower <= v80->pd_upper &&
|
||||||
|
v80->pd_upper <= v80->pd_special &&
|
||||||
|
v80->pd_special <= BLCKSZ &&
|
||||||
|
v80->pd_special == MAXALIGN(v80->pd_special) &&
|
||||||
|
!XLogRecPtrIsInvalid(*lsn = v80->pd_lsn))
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const PageHeaderData_v83 *v83 = &page->v83;
|
||||||
|
|
||||||
|
if (PageGetPageSize_v83(v83) == BLCKSZ &&
|
||||||
|
PageGetPageLayoutVersion_v83(v83) == page_layout_version &&
|
||||||
|
(v83->pd_flags & ~PD_VALID_FLAG_BITS_v83) == 0 &&
|
||||||
|
v83->pd_lower >= SizeOfPageHeaderData_v83 &&
|
||||||
|
v83->pd_lower <= v83->pd_upper &&
|
||||||
|
v83->pd_upper <= v83->pd_special &&
|
||||||
|
v83->pd_special <= BLCKSZ &&
|
||||||
|
v83->pd_special == MAXALIGN(v83->pd_special) &&
|
||||||
|
!XLogRecPtrIsInvalid(*lsn = v83->pd_lsn))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -213,6 +276,7 @@ backup_data_file(const char *from_root, const char *to_root,
|
|||||||
size_t read_len;
|
size_t read_len;
|
||||||
int errno_tmp;
|
int errno_tmp;
|
||||||
pg_crc32 crc;
|
pg_crc32 crc;
|
||||||
|
int server_version;
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
z_stream z;
|
z_stream z;
|
||||||
char outbuf[zlibOutSize];
|
char outbuf[zlibOutSize];
|
||||||
@ -268,11 +332,15 @@ backup_data_file(const char *from_root, const char *to_root,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* confirm server version */
|
||||||
|
server_version = get_server_version();
|
||||||
|
|
||||||
/* read each page and write the page excluding hole */
|
/* read each page and write the page excluding hole */
|
||||||
for (blknum = 0;
|
for (blknum = 0;
|
||||||
(read_len = fread(&page, 1, sizeof(page), in)) == sizeof(page);
|
(read_len = fread(&page, 1, sizeof(page), in)) == sizeof(page);
|
||||||
++blknum)
|
++blknum)
|
||||||
{
|
{
|
||||||
|
XLogRecPtr page_lsn;
|
||||||
int upper_offset;
|
int upper_offset;
|
||||||
int upper_length;
|
int upper_length;
|
||||||
|
|
||||||
@ -282,8 +350,8 @@ backup_data_file(const char *from_root, const char *to_root,
|
|||||||
* If a invalid data page was found, fallback to simple copy to ensure
|
* If a invalid data page was found, fallback to simple copy to ensure
|
||||||
* all pages in the file don't have BackupPageHeader.
|
* all pages in the file don't have BackupPageHeader.
|
||||||
*/
|
*/
|
||||||
if (!is_valid_header(&page.header) ||
|
if (!parse_page(&page, server_version, &page_lsn,
|
||||||
!XLogRecPtrIsInvalid(PageGetLSN(&page.header)))
|
&header.hole_offset, &header.hole_length))
|
||||||
{
|
{
|
||||||
elog(LOG, "%s fall back to simple copy", file->path);
|
elog(LOG, "%s fall back to simple copy", file->path);
|
||||||
fclose(in);
|
fclose(in);
|
||||||
@ -297,13 +365,9 @@ backup_data_file(const char *from_root, const char *to_root,
|
|||||||
file->read_size += read_len;
|
file->read_size += read_len;
|
||||||
|
|
||||||
/* if the page has not been modified since last backup, skip it */
|
/* if the page has not been modified since last backup, skip it */
|
||||||
if (lsn && !XLogRecPtrIsInvalid(PageGetLSN(&page.header)) &&
|
if (lsn && !XLogRecPtrIsInvalid(page_lsn) && XLByteLT(page_lsn, *lsn))
|
||||||
XLByteLT(PageGetLSN(&page.header), *lsn))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
header.hole_offset = page.header.pd_lower;
|
|
||||||
header.hole_length = page.header.pd_upper - page.header.pd_lower;
|
|
||||||
|
|
||||||
upper_offset = header.hole_offset + header.hole_length;
|
upper_offset = header.hole_offset + header.hole_length;
|
||||||
upper_length = BLCKSZ - upper_offset;
|
upper_length = BLCKSZ - upper_offset;
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
\! sh sql/backup_restore.sh
|
\! sh sql/backup_restore.sh
|
||||||
Line style is ascii.
|
|
||||||
CREATE TABLESPACE
|
CREATE TABLESPACE
|
||||||
CREATE DATABASE
|
CREATE DATABASE
|
||||||
# of deleted backups
|
# of deleted backups
|
||||||
|
@ -52,9 +52,9 @@ Generic options:
|
|||||||
--help show this help, then exit
|
--help show this help, then exit
|
||||||
--version output version information, then exit
|
--version output version information, then exit
|
||||||
|
|
||||||
Read the website for details. <http://rman.projects.postgresql.org/>
|
Read the website for details. <http://code.google.com/p/pg-rman/>
|
||||||
Report bugs to <rman-general@lists.pgfoundry.org>.
|
Report bugs to <http://code.google.com/p/pg-rman/issues/list>.
|
||||||
pg_rman 1.1.0
|
pg_rman 1.1.2
|
||||||
ERROR: required parameter not specified: BACKUP_PATH (-B, --backup-path)
|
ERROR: required parameter not specified: BACKUP_PATH (-B, --backup-path)
|
||||||
ERROR: required parameter not specified: BACKUP_MODE (-b, --backup-mode)
|
ERROR: required parameter not specified: BACKUP_MODE (-b, --backup-mode)
|
||||||
ERROR: required parameter not specified: ARCLOG_PATH (-A, --arclog-path)
|
ERROR: required parameter not specified: ARCLOG_PATH (-A, --arclog-path)
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
const char *PROGRAM_VERSION = "1.1.1";
|
const char *PROGRAM_VERSION = "1.1.2";
|
||||||
const char *PROGRAM_URL = "http://code.google.com/p/pg-rman/";
|
const char *PROGRAM_URL = "http://code.google.com/p/pg-rman/";
|
||||||
const char *PROGRAM_EMAIL = "http://code.google.com/p/pg-rman/issues/list";
|
const char *PROGRAM_EMAIL = "http://code.google.com/p/pg-rman/issues/list";
|
||||||
|
|
||||||
|
@ -179,6 +179,7 @@ extern int do_backup(bool smooth_checkpoint,
|
|||||||
int keep_data_generations,
|
int keep_data_generations,
|
||||||
int keep_data_days);
|
int keep_data_days);
|
||||||
extern BackupMode parse_backup_mode(const char *value, int elevel);
|
extern BackupMode parse_backup_mode(const char *value, int elevel);
|
||||||
|
extern int get_server_version(void);
|
||||||
|
|
||||||
/* in restore.c */
|
/* in restore.c */
|
||||||
extern int do_restore(const char *target_time,
|
extern int do_restore(const char *target_time,
|
||||||
|
Reference in New Issue
Block a user