Skip to content

Commit fe48c34

Browse files
author
itagaki.takahiro
committed
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
1 parent 08063f3 commit fe48c34

File tree

6 files changed

+124
-48
lines changed

6 files changed

+124
-48
lines changed

backup.c

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ static void backup_files(const char *from_root, const char *to_root,
3333
static parray *do_backup_database(parray *backup_list, bool smooth_checkpoint);
3434
static parray *do_backup_arclog(parray *backup_list);
3535
static parray *do_backup_srvlog(parray *backup_list);
36-
static void confirm_compatibility(void);
3736
static void confirm_block_size(const char *name, int blcksz);
3837
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup);
3938
static void pg_stop_backup(pgBackup *backup);
@@ -463,7 +462,7 @@ do_backup(bool smooth_checkpoint,
463462
#endif
464463

465464
/* confirm data block size and xlog block size are compatible */
466-
confirm_compatibility();
465+
(void) get_server_version();
467466

468467
/* setup cleanup callback function */
469468
in_backup = true;
@@ -585,27 +584,38 @@ do_backup(bool smooth_checkpoint,
585584
}
586585

587586
/*
588-
* Is the server compatible with this program?
587+
* get server version and confirm block sizes.
589588
*/
590-
static void
591-
confirm_compatibility(void)
589+
int
590+
get_server_version(void)
592591
{
593-
int server_version;
592+
static int server_version = 0;
593+
bool my_conn;
594594

595-
reconnect();
595+
/* return cached server version */
596+
if (server_version > 0)
597+
return server_version;
598+
599+
my_conn = (connection == NULL);
600+
601+
if (my_conn)
602+
reconnect();
596603

597604
/* confirm server version */
598605
server_version = PQserverVersion(connection);
599-
if (server_version / 100 != PG_VERSION_NUM / 100)
606+
if (server_version < 80000)
600607
elog(ERROR_PG_INCOMPATIBLE,
601-
_("version mismatch. server is %d and %s is %d."),
602-
server_version, PROGRAM_NAME, PG_VERSION_NUM);
608+
_("server version is %d, but must be 8.0 or higher."),
609+
server_version);
603610

604611
/* confirm block_size (BLCKSZ) and wal_block_size (XLOG_BLCKSZ) */
605612
confirm_block_size("block_size", BLCKSZ);
606613
confirm_block_size("wal_block_size", XLOG_BLCKSZ);
607614

608-
disconnect();
615+
if (my_conn)
616+
disconnect();
617+
618+
return server_version;
609619
}
610620

611621
static void
@@ -637,19 +647,21 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
637647
{
638648
PGresult *res;
639649
const char *params[2];
650+
int server_version;
640651

641652
params[0] = label;
642653

643654
reconnect();
644-
if (PQserverVersion(connection) >= 80400)
655+
server_version = get_server_version();
656+
if (server_version >= 80400)
645657
{
646658
params[1] = smooth ? "false" : "true";
647659
res = execute("SELECT * from pg_xlogfile_name_offset(pg_start_backup($1, $2))", 2, params);
648660
}
649661
else
650662
{
651663
/* v8.3 always uses smooth checkpoint */
652-
if (!smooth && PQserverVersion(connection) >= 80300)
664+
if (!smooth && server_version >= 80300)
653665
command("CHECKPOINT", 0, NULL);
654666
res = execute("SELECT * from pg_xlogfile_name_offset(pg_start_backup($1))", 1, params);
655667
}

data.c

Lines changed: 94 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,54 @@ doInflate(z_stream *zp, size_t in_size, size_t out_size,void *inbuf,
152152
}
153153
#endif
154154

155+
#define PG_PAGE_LAYOUT_VERSION_v80 2 /* 8.0 */
156+
#define PG_PAGE_LAYOUT_VERSION_v81 3 /* 8.1 - 8.2 */
157+
#define PG_PAGE_LAYOUT_VERSION_v83 4 /* 8.3 - */
158+
159+
/* 80000 <= PG_VERSION_NUM < 80300 */
160+
typedef struct PageHeaderData_v80
161+
{
162+
XLogRecPtr pd_lsn;
163+
TimeLineID pd_tli;
164+
LocationIndex pd_lower;
165+
LocationIndex pd_upper;
166+
LocationIndex pd_special;
167+
uint16 pd_pagesize_version;
168+
ItemIdData pd_linp[1];
169+
} PageHeaderData_v80;
170+
171+
#define PageGetPageSize_v80(page) \
172+
((Size) ((page)->pd_pagesize_version & (uint16) 0xFF00))
173+
#define PageGetPageLayoutVersion_v80(page) \
174+
((page)->pd_pagesize_version & 0x00FF)
175+
#define SizeOfPageHeaderData_v80 (offsetof(PageHeaderData_v80, pd_linp))
176+
177+
/* 80300 <= PG_VERSION_NUM */
178+
typedef struct PageHeaderData_v83
179+
{
180+
XLogRecPtr pd_lsn;
181+
uint16 pd_tli;
182+
uint16 pd_flags;
183+
LocationIndex pd_lower;
184+
LocationIndex pd_upper;
185+
LocationIndex pd_special;
186+
uint16 pd_pagesize_version;
187+
TransactionId pd_prune_xid;
188+
ItemIdData pd_linp[1];
189+
} PageHeaderData_v83;
190+
191+
#define PageGetPageSize_v83(page) \
192+
((Size) ((page)->pd_pagesize_version & (uint16) 0xFF00))
193+
#define PageGetPageLayoutVersion_v83(page) \
194+
((page)->pd_pagesize_version & 0x00FF)
195+
#define SizeOfPageHeaderData_v83 (offsetof(PageHeaderData_v83, pd_linp))
196+
#define PD_VALID_FLAG_BITS_v83 0x0007
197+
155198
typedef union DataPage
156199
{
157-
PageHeaderData header;
158-
char data[BLCKSZ];
200+
PageHeaderData_v80 v80; /* 8.0 - 8.2 */
201+
PageHeaderData_v83 v83; /* 8.3 - */
202+
char data[BLCKSZ];
159203
} DataPage;
160204

161205
typedef struct BackupPageHeader
@@ -166,32 +210,51 @@ typedef struct BackupPageHeader
166210
} BackupPageHeader;
167211

168212
static bool
169-
is_valid_header(const PageHeader page)
213+
parse_page(const DataPage *page, int server_version,
214+
XLogRecPtr *lsn, uint16 *offset, uint16 *length)
170215
{
171-
const char *pagebytes;
172-
int i;
216+
uint16 page_layout_version;
217+
218+
/* Determine page layout version */
219+
if (server_version < 80100)
220+
page_layout_version = PG_PAGE_LAYOUT_VERSION_v80;
221+
else if (server_version < 80300)
222+
page_layout_version = PG_PAGE_LAYOUT_VERSION_v81;
223+
else
224+
page_layout_version = PG_PAGE_LAYOUT_VERSION_v83;
173225

174226
/* Check normal case */
175-
if (PageGetPageSize(page) == BLCKSZ &&
176-
PageGetPageLayoutVersion(page) == PG_PAGE_LAYOUT_VERSION &&
177-
#if PG_VERSION_NUM >= 80300
178-
(page->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
179-
#endif
180-
page->pd_lower >= SizeOfPageHeaderData &&
181-
page->pd_lower <= page->pd_upper &&
182-
page->pd_upper <= page->pd_special &&
183-
page->pd_special <= BLCKSZ &&
184-
page->pd_special == MAXALIGN(page->pd_special))
185-
return true;
186-
187-
/* Check all-zeroes case */
188-
pagebytes = (char *) page;
189-
for (i = 0; i < BLCKSZ; i++)
227+
if (server_version < 80300)
190228
{
191-
if (pagebytes[i] != 0)
192-
return false;
229+
const PageHeaderData_v80 *v80 = &page->v80;
230+
231+
if (PageGetPageSize_v80(v80) == BLCKSZ &&
232+
PageGetPageLayoutVersion_v80(v80) == page_layout_version &&
233+
v80->pd_lower >= SizeOfPageHeaderData_v80 &&
234+
v80->pd_lower <= v80->pd_upper &&
235+
v80->pd_upper <= v80->pd_special &&
236+
v80->pd_special <= BLCKSZ &&
237+
v80->pd_special == MAXALIGN(v80->pd_special) &&
238+
!XLogRecPtrIsInvalid(*lsn = v80->pd_lsn))
239+
return true;
193240
}
194-
return true;
241+
else
242+
{
243+
const PageHeaderData_v83 *v83 = &page->v83;
244+
245+
if (PageGetPageSize_v83(v83) == BLCKSZ &&
246+
PageGetPageLayoutVersion_v83(v83) == page_layout_version &&
247+
(v83->pd_flags & ~PD_VALID_FLAG_BITS_v83) == 0 &&
248+
v83->pd_lower >= SizeOfPageHeaderData_v83 &&
249+
v83->pd_lower <= v83->pd_upper &&
250+
v83->pd_upper <= v83->pd_special &&
251+
v83->pd_special <= BLCKSZ &&
252+
v83->pd_special == MAXALIGN(v83->pd_special) &&
253+
!XLogRecPtrIsInvalid(*lsn = v83->pd_lsn))
254+
return true;
255+
}
256+
257+
return false;
195258
}
196259

197260
/*
@@ -213,6 +276,7 @@ backup_data_file(const char *from_root, const char *to_root,
213276
size_t read_len;
214277
int errno_tmp;
215278
pg_crc32 crc;
279+
int server_version;
216280
#ifdef HAVE_LIBZ
217281
z_stream z;
218282
char outbuf[zlibOutSize];
@@ -268,11 +332,15 @@ backup_data_file(const char *from_root, const char *to_root,
268332
}
269333
#endif
270334

335+
/* confirm server version */
336+
server_version = get_server_version();
337+
271338
/* read each page and write the page excluding hole */
272339
for (blknum = 0;
273340
(read_len = fread(&page, 1, sizeof(page), in)) == sizeof(page);
274341
++blknum)
275342
{
343+
XLogRecPtr page_lsn;
276344
int upper_offset;
277345
int upper_length;
278346

@@ -282,8 +350,8 @@ backup_data_file(const char *from_root, const char *to_root,
282350
* If a invalid data page was found, fallback to simple copy to ensure
283351
* all pages in the file don't have BackupPageHeader.
284352
*/
285-
if (!is_valid_header(&page.header) ||
286-
!XLogRecPtrIsInvalid(PageGetLSN(&page.header)))
353+
if (!parse_page(&page, server_version, &page_lsn,
354+
&header.hole_offset, &header.hole_length))
287355
{
288356
elog(LOG, "%s fall back to simple copy", file->path);
289357
fclose(in);
@@ -297,13 +365,9 @@ backup_data_file(const char *from_root, const char *to_root,
297365
file->read_size += read_len;
298366

299367
/* if the page has not been modified since last backup, skip it */
300-
if (lsn && !XLogRecPtrIsInvalid(PageGetLSN(&page.header)) &&
301-
XLByteLT(PageGetLSN(&page.header), *lsn))
368+
if (lsn && !XLogRecPtrIsInvalid(page_lsn) && XLByteLT(page_lsn, *lsn))
302369
continue;
303370

304-
header.hole_offset = page.header.pd_lower;
305-
header.hole_length = page.header.pd_upper - page.header.pd_lower;
306-
307371
upper_offset = header.hole_offset + header.hole_length;
308372
upper_length = BLCKSZ - upper_offset;
309373

expected/backup_restore.out

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
\! sh sql/backup_restore.sh
2-
Line style is ascii.
32
CREATE TABLESPACE
43
CREATE DATABASE
54
# of deleted backups

expected/option.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ Generic options:
5252
--help show this help, then exit
5353
--version output version information, then exit
5454

55-
Read the website for details. <http://rman.projects.postgresql.org/>
56-
Report bugs to <rman-general@lists.pgfoundry.org>.
57-
pg_rman 1.1.0
55+
Read the website for details. <http://code.google.com/p/pg-rman/>
56+
Report bugs to <http://code.google.com/p/pg-rman/issues/list>.
57+
pg_rman 1.1.2
5858
ERROR: required parameter not specified: BACKUP_PATH (-B, --backup-path)
5959
ERROR: required parameter not specified: BACKUP_MODE (-b, --backup-mode)
6060
ERROR: required parameter not specified: ARCLOG_PATH (-A, --arclog-path)

pg_rman.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include <stdlib.h>
1414
#include <time.h>
1515

16-
const char *PROGRAM_VERSION = "1.1.1";
16+
const char *PROGRAM_VERSION = "1.1.2";
1717
const char *PROGRAM_URL = "http://code.google.com/p/pg-rman/";
1818
const char *PROGRAM_EMAIL = "http://code.google.com/p/pg-rman/issues/list";
1919

pg_rman.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ extern int do_backup(bool smooth_checkpoint,
179179
int keep_data_generations,
180180
int keep_data_days);
181181
extern BackupMode parse_backup_mode(const char *value, int elevel);
182+
extern int get_server_version(void);
182183

183184
/* in restore.c */
184185
extern int do_restore(const char *target_time,

0 commit comments

Comments
 (0)