mirror of
https://github.com/postgrespro/pg_probackup.git
synced 2024-11-24 08:52:38 +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:
parent
08063f31f9
commit
fe48c34b5e
38
backup.c
38
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_arclog(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 pg_start_backup(const char *label, bool smooth, pgBackup *backup);
|
||||
static void pg_stop_backup(pgBackup *backup);
|
||||
@ -463,7 +462,7 @@ do_backup(bool smooth_checkpoint,
|
||||
#endif
|
||||
|
||||
/* confirm data block size and xlog block size are compatible */
|
||||
confirm_compatibility();
|
||||
(void) get_server_version();
|
||||
|
||||
/* setup cleanup callback function */
|
||||
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
|
||||
confirm_compatibility(void)
|
||||
int
|
||||
get_server_version(void)
|
||||
{
|
||||
int server_version;
|
||||
static int server_version = 0;
|
||||
bool my_conn;
|
||||
|
||||
reconnect();
|
||||
/* return cached server version */
|
||||
if (server_version > 0)
|
||||
return server_version;
|
||||
|
||||
my_conn = (connection == NULL);
|
||||
|
||||
if (my_conn)
|
||||
reconnect();
|
||||
|
||||
/* confirm server version */
|
||||
server_version = PQserverVersion(connection);
|
||||
if (server_version / 100 != PG_VERSION_NUM / 100)
|
||||
if (server_version < 80000)
|
||||
elog(ERROR_PG_INCOMPATIBLE,
|
||||
_("version mismatch. server is %d and %s is %d."),
|
||||
server_version, PROGRAM_NAME, PG_VERSION_NUM);
|
||||
_("server version is %d, but must be 8.0 or higher."),
|
||||
server_version);
|
||||
|
||||
/* confirm block_size (BLCKSZ) and wal_block_size (XLOG_BLCKSZ) */
|
||||
confirm_block_size("block_size", BLCKSZ);
|
||||
confirm_block_size("wal_block_size", XLOG_BLCKSZ);
|
||||
|
||||
disconnect();
|
||||
if (my_conn)
|
||||
disconnect();
|
||||
|
||||
return server_version;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -637,11 +647,13 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
|
||||
{
|
||||
PGresult *res;
|
||||
const char *params[2];
|
||||
int server_version;
|
||||
|
||||
params[0] = label;
|
||||
|
||||
reconnect();
|
||||
if (PQserverVersion(connection) >= 80400)
|
||||
server_version = get_server_version();
|
||||
if (server_version >= 80400)
|
||||
{
|
||||
params[1] = smooth ? "false" : "true";
|
||||
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
|
||||
{
|
||||
/* v8.3 always uses smooth checkpoint */
|
||||
if (!smooth && PQserverVersion(connection) >= 80300)
|
||||
if (!smooth && server_version >= 80300)
|
||||
command("CHECKPOINT", 0, NULL);
|
||||
res = execute("SELECT * from pg_xlogfile_name_offset(pg_start_backup($1))", 1, params);
|
||||
}
|
||||
|
124
data.c
124
data.c
@ -152,10 +152,54 @@ doInflate(z_stream *zp, size_t in_size, size_t out_size,void *inbuf,
|
||||
}
|
||||
#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
|
||||
{
|
||||
PageHeaderData header;
|
||||
char data[BLCKSZ];
|
||||
PageHeaderData_v80 v80; /* 8.0 - 8.2 */
|
||||
PageHeaderData_v83 v83; /* 8.3 - */
|
||||
char data[BLCKSZ];
|
||||
} DataPage;
|
||||
|
||||
typedef struct BackupPageHeader
|
||||
@ -166,32 +210,51 @@ typedef struct BackupPageHeader
|
||||
} BackupPageHeader;
|
||||
|
||||
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;
|
||||
int i;
|
||||
uint16 page_layout_version;
|
||||
|
||||
/* 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 */
|
||||
if (PageGetPageSize(page) == BLCKSZ &&
|
||||
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 (server_version < 80300)
|
||||
{
|
||||
if (pagebytes[i] != 0)
|
||||
return false;
|
||||
const PageHeaderData_v80 *v80 = &page->v80;
|
||||
|
||||
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;
|
||||
int errno_tmp;
|
||||
pg_crc32 crc;
|
||||
int server_version;
|
||||
#ifdef HAVE_LIBZ
|
||||
z_stream z;
|
||||
char outbuf[zlibOutSize];
|
||||
@ -268,11 +332,15 @@ backup_data_file(const char *from_root, const char *to_root,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* confirm server version */
|
||||
server_version = get_server_version();
|
||||
|
||||
/* read each page and write the page excluding hole */
|
||||
for (blknum = 0;
|
||||
(read_len = fread(&page, 1, sizeof(page), in)) == sizeof(page);
|
||||
++blknum)
|
||||
{
|
||||
XLogRecPtr page_lsn;
|
||||
int upper_offset;
|
||||
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
|
||||
* all pages in the file don't have BackupPageHeader.
|
||||
*/
|
||||
if (!is_valid_header(&page.header) ||
|
||||
!XLogRecPtrIsInvalid(PageGetLSN(&page.header)))
|
||||
if (!parse_page(&page, server_version, &page_lsn,
|
||||
&header.hole_offset, &header.hole_length))
|
||||
{
|
||||
elog(LOG, "%s fall back to simple copy", file->path);
|
||||
fclose(in);
|
||||
@ -297,13 +365,9 @@ backup_data_file(const char *from_root, const char *to_root,
|
||||
file->read_size += read_len;
|
||||
|
||||
/* if the page has not been modified since last backup, skip it */
|
||||
if (lsn && !XLogRecPtrIsInvalid(PageGetLSN(&page.header)) &&
|
||||
XLByteLT(PageGetLSN(&page.header), *lsn))
|
||||
if (lsn && !XLogRecPtrIsInvalid(page_lsn) && XLByteLT(page_lsn, *lsn))
|
||||
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_length = BLCKSZ - upper_offset;
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
\! sh sql/backup_restore.sh
|
||||
Line style is ascii.
|
||||
CREATE TABLESPACE
|
||||
CREATE DATABASE
|
||||
# of deleted backups
|
||||
|
@ -52,9 +52,9 @@ Generic options:
|
||||
--help show this help, then exit
|
||||
--version output version information, then exit
|
||||
|
||||
Read the website for details. <http://rman.projects.postgresql.org/>
|
||||
Report bugs to <rman-general@lists.pgfoundry.org>.
|
||||
pg_rman 1.1.0
|
||||
Read the website for details. <http://code.google.com/p/pg-rman/>
|
||||
Report bugs to <http://code.google.com/p/pg-rman/issues/list>.
|
||||
pg_rman 1.1.2
|
||||
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: ARCLOG_PATH (-A, --arclog-path)
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <stdlib.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_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_days);
|
||||
extern BackupMode parse_backup_mode(const char *value, int elevel);
|
||||
extern int get_server_version(void);
|
||||
|
||||
/* in restore.c */
|
||||
extern int do_restore(const char *target_time,
|
||||
|
Loading…
Reference in New Issue
Block a user