Skip to content

Commit ed8fbca

Browse files
committed
Make validate logic like restore. issue #5
1 parent 5e37fc6 commit ed8fbca

File tree

5 files changed

+277
-49
lines changed

5 files changed

+277
-49
lines changed

parsexlog.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ static const char *RmgrNames[RM_MAX_ID + 1] = {
3030
};
3131

3232
static void extractPageInfo(XLogReaderState *record);
33+
static bool getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime);
3334

3435
static int xlogreadfd = -1;
3536
static XLogSegNo xlogreadsegno = -1;
@@ -175,7 +176,7 @@ SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
175176
static void
176177
extractPageInfo(XLogReaderState *record)
177178
{
178-
int block_id;
179+
uint8 block_id;
179180
RmgrId rmid = XLogRecGetRmid(record);
180181
uint8 info = XLogRecGetInfo(record);
181182
uint8 rminfo = info & ~XLR_INFO_MASK;
@@ -240,3 +241,39 @@ extractPageInfo(XLogReaderState *record)
240241
process_block_change(forknum, rnode, blkno);
241242
}
242243
}
244+
245+
/*
246+
* Extract timestamp from WAL record.
247+
*
248+
* If the record contains a timestamp, returns true, and saves the timestamp
249+
* in *recordXtime. If the record type has no timestamp, returns false.
250+
* Currently, only transaction commit/abort records and restore points contain
251+
* timestamps.
252+
*/
253+
static bool
254+
getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime)
255+
{
256+
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
257+
uint8 xact_info = info & XLOG_XACT_OPMASK;
258+
uint8 rmid = XLogRecGetRmid(record);
259+
260+
if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
261+
{
262+
*recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
263+
return true;
264+
}
265+
if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT ||
266+
xact_info == XLOG_XACT_COMMIT_PREPARED))
267+
{
268+
*recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
269+
return true;
270+
}
271+
if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT ||
272+
xact_info == XLOG_XACT_ABORT_PREPARED))
273+
{
274+
*recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
275+
return true;
276+
}
277+
return false;
278+
}
279+

pg_probackup.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,18 +206,25 @@ main(int argc, char *argv[])
206206
if (res != 0)
207207
return res;
208208

209-
do_validate(current.start_time);
209+
do_validate_last();
210210
}
211211
else if (pg_strcasecmp(cmd, "restore") == 0)
212-
return do_restore(backup_id, target_time, target_xid,
213-
target_inclusive, target_tli);
212+
return do_restore(backup_id,
213+
target_time,
214+
target_xid,
215+
target_inclusive,
216+
target_tli);
214217
else if (pg_strcasecmp(cmd, "show") == 0)
215218
return do_show(backup_id);
216219
else if (pg_strcasecmp(cmd, "validate") == 0)
217220
{
218221
if (backup_id == 0)
219222
elog(ERROR, "you must specify backup-ID for this command");
220-
return do_validate(backup_id);
223+
return do_validate(backup_id,
224+
target_time,
225+
target_xid,
226+
target_inclusive,
227+
target_tli);
221228
}
222229
else if (pg_strcasecmp(cmd, "delete") == 0)
223230
return do_delete(backup_id);

pg_probackup.h

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,17 @@ extern int do_restore(time_t backup_id,
221221
const char *target_xid,
222222
const char *target_inclusive,
223223
TimeLineID target_tli);
224+
extern bool satisfy_timeline(const parray *timelines, const pgBackup *backup);
225+
extern bool satisfy_recovery_target(const pgBackup *backup,
226+
const pgRecoveryTarget *rt);
227+
extern TimeLineID get_fullbackup_timeline(parray *backups,
228+
const pgRecoveryTarget *rt);
229+
extern TimeLineID findNewestTimeLine(TimeLineID startTLI);
230+
extern parray * readTimeLineHistory(TimeLineID targetTLI);
231+
extern pgRecoveryTarget *checkIfCreateRecoveryConf(
232+
const char *target_time,
233+
const char *target_xid,
234+
const char *target_inclusive);
224235

225236
/* in init.c */
226237
extern int do_init(void);
@@ -240,7 +251,12 @@ extern char *slurpFile(const char *datadir,
240251
bool safe);
241252

242253
/* in validate.c */
243-
extern int do_validate(time_t backup_id);
254+
extern int do_validate(time_t backup_id,
255+
const char *target_time,
256+
const char *target_xid,
257+
const char *target_inclusive,
258+
TimeLineID target_tli);
259+
extern void do_validate_last(void);
244260
extern void pgBackupValidate(pgBackup *backup,
245261
bool size_only,
246262
bool for_get_timeline);
@@ -316,4 +332,46 @@ extern uint64 get_system_identifier(bool safe);
316332
/* in status.c */
317333
extern bool is_pg_running(void);
318334

335+
/* some from access/xact.h */
336+
/*
337+
* XLOG allows to store some information in high 4 bits of log record xl_info
338+
* field. We use 3 for the opcode, and one about an optional flag variable.
339+
*/
340+
#define XLOG_XACT_COMMIT 0x00
341+
#define XLOG_XACT_PREPARE 0x10
342+
#define XLOG_XACT_ABORT 0x20
343+
#define XLOG_XACT_COMMIT_PREPARED 0x30
344+
#define XLOG_XACT_ABORT_PREPARED 0x40
345+
#define XLOG_XACT_ASSIGNMENT 0x50
346+
/* free opcode 0x60 */
347+
/* free opcode 0x70 */
348+
349+
/* mask for filtering opcodes out of xl_info */
350+
#define XLOG_XACT_OPMASK 0x70
351+
352+
typedef struct xl_xact_commit
353+
{
354+
TimestampTz xact_time; /* time of commit */
355+
356+
/* xl_xact_xinfo follows if XLOG_XACT_HAS_INFO */
357+
/* xl_xact_dbinfo follows if XINFO_HAS_DBINFO */
358+
/* xl_xact_subxacts follows if XINFO_HAS_SUBXACT */
359+
/* xl_xact_relfilenodes follows if XINFO_HAS_RELFILENODES */
360+
/* xl_xact_invals follows if XINFO_HAS_INVALS */
361+
/* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */
362+
/* xl_xact_origin follows if XINFO_HAS_ORIGIN, stored unaligned! */
363+
} xl_xact_commit;
364+
365+
typedef struct xl_xact_abort
366+
{
367+
TimestampTz xact_time; /* time of abort */
368+
369+
/* xl_xact_xinfo follows if XLOG_XACT_HAS_INFO */
370+
/* No db_info required */
371+
/* xl_xact_subxacts follows if HAS_SUBXACT */
372+
/* xl_xact_relfilenodes follows if HAS_RELFILENODES */
373+
/* No invalidation messages needed. */
374+
/* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */
375+
} xl_xact_abort;
376+
319377
#endif /* PG_PROBACKUP_H */

restore.c

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,13 @@ static void create_recovery_conf(time_t backup_id,
2929
const char *target_xid,
3030
const char *target_inclusive,
3131
TimeLineID target_tli);
32-
static pgRecoveryTarget *checkIfCreateRecoveryConf(const char *target_time,
33-
const char *target_xid,
34-
const char *target_inclusive);
35-
static parray * readTimeLineHistory(TimeLineID targetTLI);
36-
static bool satisfy_timeline(const parray *timelines, const pgBackup *backup);
37-
static bool satisfy_recovery_target(const pgBackup *backup,
38-
const pgRecoveryTarget *rt);
39-
static TimeLineID get_fullbackup_timeline(parray *backups,
40-
const pgRecoveryTarget *rt);
4132
static void print_backup_lsn(const pgBackup *backup);
4233
static void search_next_wal(const char *path,
4334
XLogRecPtr *need_lsn,
4435
parray *timelines);
4536
static void restore_files(void *arg);
4637

47-
TimeLineID findNewestTimeLine(TimeLineID startTLI);
38+
4839
bool existsTimeLineHistory(TimeLineID probeTLI);
4940

5041

@@ -63,9 +54,11 @@ do_restore(time_t backup_id,
6354
TimeLineID backup_tli;
6455
TimeLineID newest_tli;
6556
parray *backups;
66-
pgBackup *base_backup = NULL;
57+
6758
parray *files;
6859
parray *timelines;
60+
pgBackup *base_backup = NULL;
61+
pgBackup *dest_backup = NULL;
6962
pgRecoveryTarget *rt = NULL;
7063
XLogRecPtr need_lsn;
7164
bool backup_id_found = false;
@@ -126,15 +119,25 @@ do_restore(time_t backup_id,
126119
continue;
127120

128121
if (backup_id == base_backup->start_time &&
129-
base_backup->status == BACKUP_STATUS_OK
130-
)
122+
base_backup->status == BACKUP_STATUS_OK)
123+
{
131124
backup_id_found = true;
125+
dest_backup = base_backup;
126+
}
132127

133128
if (backup_id == base_backup->start_time &&
134129
base_backup->status != BACKUP_STATUS_OK
135130
)
136131
elog(ERROR, "given backup %s is %s", base36enc(backup_id), status2str(base_backup->status));
137132

133+
if (dest_backup != NULL &&
134+
base_backup->backup_mode == BACKUP_MODE_FULL &&
135+
base_backup->status != BACKUP_STATUS_OK)
136+
elog(ERROR, "base backup %s for given backup %s is %s",
137+
base36enc(base_backup->start_time),
138+
base36enc(dest_backup->start_time),
139+
status2str(base_backup->status));
140+
138141
if (base_backup->backup_mode < BACKUP_MODE_FULL ||
139142
base_backup->status != BACKUP_STATUS_OK)
140143
continue;
@@ -522,7 +525,7 @@ create_recovery_conf(time_t backup_id,
522525
* specified timeline ID.
523526
* based on readTimeLineHistory() in xlog.c
524527
*/
525-
static parray *
528+
parray *
526529
readTimeLineHistory(TimeLineID targetTLI)
527530
{
528531
parray *result;
@@ -632,7 +635,7 @@ readTimeLineHistory(TimeLineID targetTLI)
632635
return result;
633636
}
634637

635-
static bool
638+
bool
636639
satisfy_recovery_target(const pgBackup *backup, const pgRecoveryTarget *rt)
637640
{
638641
if (rt->xid_specified)
@@ -644,7 +647,7 @@ satisfy_recovery_target(const pgBackup *backup, const pgRecoveryTarget *rt)
644647
return true;
645648
}
646649

647-
static bool
650+
bool
648651
satisfy_timeline(const parray *timelines, const pgBackup *backup)
649652
{
650653
int i;
@@ -659,7 +662,7 @@ satisfy_timeline(const parray *timelines, const pgBackup *backup)
659662
}
660663

661664
/* get TLI of the latest full backup */
662-
static TimeLineID
665+
TimeLineID
663666
get_fullbackup_timeline(parray *backups, const pgRecoveryTarget *rt)
664667
{
665668
int i;
@@ -769,7 +772,7 @@ search_next_wal(const char *path, XLogRecPtr *need_lsn, parray *timelines)
769772
}
770773
}
771774

772-
static pgRecoveryTarget *
775+
pgRecoveryTarget *
773776
checkIfCreateRecoveryConf(const char *target_time,
774777
const char *target_xid,
775778
const char *target_inclusive)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy