1
0
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:
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_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
View File

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

View File

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

View File

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

View File

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

View File

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