1
0
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:
itagaki.takahiro 2009-12-13 08:54:34 +00:00
parent 08063f31f9
commit fe48c34b5e
6 changed files with 124 additions and 48 deletions

View File

@ -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
View File

@ -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;

View File

@ -1,5 +1,4 @@
\! sh sql/backup_restore.sh
Line style is ascii.
CREATE TABLESPACE
CREATE DATABASE
# of deleted backups

View File

@ -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)

View File

@ -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";

View File

@ -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,