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

+38-1
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

+11-4
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

+59-1
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

+21-18
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)