Skip to content

Commit bbf67e5

Browse files
committed
Add --snapshot option to pg_basebackup
1 parent 1460e9d commit bbf67e5

File tree

8 files changed

+99
-5
lines changed

8 files changed

+99
-5
lines changed

src/backend/replication/basebackup.c

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "storage/fd.h"
3838
#include "storage/ipc.h"
3939
#include "storage/reinit.h"
40+
#include "storage/snapfs.h"
4041
#include "utils/builtins.h"
4142
#include "utils/ps_status.h"
4243
#include "utils/relcache.h"
@@ -52,6 +53,7 @@ typedef struct
5253
bool includewal;
5354
uint32 maxrate;
5455
bool sendtblspcmapfile;
56+
SnapshotId snapshot;
5557
} basebackup_options;
5658

5759

@@ -234,6 +236,7 @@ perform_base_backup(basebackup_options *opt)
234236
tblspc_map_file = makeStringInfo();
235237

236238
total_checksum_failures = 0;
239+
sfs_backend_snapshot = opt->snapshot;
237240

238241
startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
239242
labelfile, &tablespaces,
@@ -643,6 +646,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
643646
bool o_maxrate = false;
644647
bool o_tablespace_map = false;
645648
bool o_noverify_checksums = false;
649+
bool o_snapshot = false;
646650

647651
MemSet(opt, 0, sizeof(*opt));
648652
foreach(lopt, options)
@@ -658,6 +662,15 @@ parse_basebackup_options(List *options, basebackup_options *opt)
658662
opt->label = strVal(defel->arg);
659663
o_label = true;
660664
}
665+
else if (strcmp(defel->defname, "snapshot") == 0)
666+
{
667+
if (o_snapshot)
668+
ereport(ERROR,
669+
(errcode(ERRCODE_SYNTAX_ERROR),
670+
errmsg("duplicate option \"%s\"", defel->defname)));
671+
opt->snapshot = intVal(defel->arg);
672+
o_snapshot = true;
673+
}
661674
else if (strcmp(defel->defname, "progress") == 0)
662675
{
663676
if (o_progress)
@@ -764,8 +777,10 @@ SendBaseBackup(BaseBackupCmd *cmd)
764777
opt.label);
765778
set_ps_display(activitymsg, false);
766779
}
767-
780+
sfs_basebackup = true;
768781
perform_base_backup(&opt);
782+
sfs_basebackup = false;
783+
sfs_backend_snapshot = SFS_INVALID_SNAPSHOT;
769784
}
770785

771786
static void
@@ -1140,6 +1155,10 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
11401155
continue;
11411156
}
11421157

1158+
/* Do not backup snapfs files */
1159+
if (is_snapfs_file(de->d_name))
1160+
continue;
1161+
11431162
snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path, de->d_name);
11441163

11451164
/* Skip pg_control here to back up it last */
@@ -1373,6 +1392,12 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
13731392
int segmentno = 0;
13741393
char *segmentpath;
13751394
bool verify_checksum = false;
1395+
SnapshotId current_snapshot;
1396+
File file = -1;
1397+
1398+
current_snapshot = sfs_backend_snapshot != SFS_INVALID_SNAPSHOT ? sfs_backend_snapshot : ControlFile->active_snapshot;
1399+
if (current_snapshot != SFS_INVALID_SNAPSHOT)
1400+
file = PathNameOpenFile(readfilename, O_RDONLY|PG_BINARY);
13761401

13771402
fp = AllocateFile(readfilename, "rb");
13781403
if (fp == NULL)
@@ -1523,6 +1548,32 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
15231548
}
15241549
}
15251550

1551+
if (current_snapshot != SFS_INVALID_SNAPSHOT)
1552+
{
1553+
for (i = 0; i < cnt / BLCKSZ; i++)
1554+
{
1555+
int rc;
1556+
page = buf + BLCKSZ * i;
1557+
rc = FileRead(file, page, BLCKSZ, WAIT_EVENT_DATA_FILE_READ);
1558+
if (rc < 0)
1559+
ereport(ERROR,
1560+
(errmsg("base backup could not read snapshot file, aborting backup")));
1561+
}
1562+
}
1563+
1564+
/* Remove information about snapshots from control file */
1565+
if (SFS_KEEPING_SNAPSHOT() && strcmp(readfilename, XLOG_CONTROL_FILE) == 0)
1566+
{
1567+
ControlFileData* ctl = (ControlFileData*)buf;
1568+
ctl->oldest_snapshot = 1;
1569+
ctl->recent_snapshot = SFS_INVALID_SNAPSHOT;
1570+
ctl->active_snapshot = SFS_INVALID_SNAPSHOT;
1571+
INIT_CRC32C(ctl->crc);
1572+
COMP_CRC32C(ctl->crc,
1573+
(char *) ctl,
1574+
offsetof(ControlFileData, crc));
1575+
FIN_CRC32C(ctl->crc);
1576+
}
15261577
/* Send the chunk as a CopyData message */
15271578
if (pq_putmessage('d', buf, cnt))
15281579
ereport(ERROR,
@@ -1541,6 +1592,8 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
15411592
break;
15421593
}
15431594
}
1595+
if (file >= 0)
1596+
FileClose(file);
15441597

15451598
/* If the file was truncated while we were sending it, pad it with zeros */
15461599
if (len < statbuf->st_size)

src/backend/replication/repl_gram.y

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static SQLCmd *make_sqlcmd(void);
7070
%token K_DROP_REPLICATION_SLOT
7171
%token K_TIMELINE_HISTORY
7272
%token K_LABEL
73+
%token K_SNAPSHOT
7374
%token K_PROGRESS
7475
%token K_FAST
7576
%token K_WAIT
@@ -179,6 +180,11 @@ base_backup_opt:
179180
$$ = makeDefElem("label",
180181
(Node *)makeString($2), -1);
181182
}
183+
| K_SNAPSHOT UCONST
184+
{
185+
$$ = makeDefElem("snapshot",
186+
(Node *)makeInteger($2), -1);
187+
}
182188
| K_PROGRESS
183189
{
184190
$$ = makeDefElem("progress",

src/backend/replication/repl_scanner.l

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ FAST { return K_FAST; }
8787
IDENTIFY_SYSTEM { return K_IDENTIFY_SYSTEM; }
8888
SHOW { return K_SHOW; }
8989
LABEL { return K_LABEL; }
90+
SNAPSHOT { return K_SNAPSHOT; }
9091
NOWAIT { return K_NOWAIT; }
9192
PROGRESS { return K_PROGRESS; }
9293
MAX_RATE { return K_MAX_RATE; }

src/backend/storage/file/fd.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,9 +2054,24 @@ FileRead(File file, char *buffer, int amount, uint32 wait_event_info)
20542054
elog(ERROR, "[SFS] Field to read snapshot file: %m");
20552055

20562056
pgstat_report_wait_end();
2057+
if (sfs_basebackup)
2058+
{
2059+
/* We should move file position in case of base backup to avoid explicit seeks */
2060+
vfdP->seekPos += amount;
2061+
}
20572062
return amount;
20582063
}
20592064
}
2065+
/*
2066+
* In case of performing pg_basebackup of particular snapshot
2067+
* we are interested only in reading original image of the page.
2068+
*/
2069+
if (sfs_basebackup)
2070+
{
2071+
/* We should move file position in case of base backup to avoid explicit seeks */
2072+
vfdP->seekPos += amount;
2073+
return 0;
2074+
}
20602075
}
20612076
retry:
20622077
pgstat_report_wait_start(wait_event_info);
@@ -2174,8 +2189,6 @@ FileWrite(File file, char *buffer, int amount, uint32 wait_event_info)
21742189
char orig_block[BLCKSZ];
21752190
int rc;
21762191

2177-
vfdP->snap_map->offs[block_no] = snap_offs + 1;
2178-
21792192
rc = sfs_read_file(vfdP->fd, orig_block, BLCKSZ);
21802193
if (rc < 0)
21812194
elog(ERROR, "[SFS] Could not read file: %m");
@@ -2190,6 +2203,9 @@ FileWrite(File file, char *buffer, int amount, uint32 wait_event_info)
21902203

21912204
if (!sfs_write_file(vfdP->snap_fd, orig_block, BLCKSZ))
21922205
elog(ERROR, "[SFS] Could not write file: %m");
2206+
2207+
/* Update map only after saving original page */
2208+
vfdP->snap_map->offs[block_no] = snap_offs + 1;
21932209
}
21942210
}
21952211

@@ -3450,6 +3466,13 @@ RemovePgTempRelationFilesInDbspace(const char *dbspacedirname)
34503466
FreeDir(dbspace_dir);
34513467
}
34523468

3469+
/* <file>.snap.SNAPSHOT or <file>.snapmap.SNAPSHOT */
3470+
bool
3471+
is_snapfs_file(const char* name)
3472+
{
3473+
return strstr(name, ".snap") != NULL;
3474+
}
3475+
34533476
/* t<digits>_<digits>, or t<digits>_<digits>_<forkname> */
34543477
bool
34553478
looks_like_temp_rel_name(const char *name)

src/backend/storage/file/snapfs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
SnapshotId sfs_backend_snapshot = SFS_INVALID_SNAPSHOT;
4343
SnapshotId sfs_active_snapshot;
44+
bool sfs_basebackup;
4445

4546
int
4647
sfs_msync(SnapshotMap * map)

src/bin/pg_basebackup/pg_basebackup.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static bool temp_replication_slot = true;
9999
static bool create_slot = false;
100100
static bool no_slot = false;
101101
static bool verify_checksums = true;
102+
static char *snapshot = NULL;
102103

103104
static bool success = false;
104105
static bool made_new_pgdata = false;
@@ -366,6 +367,7 @@ usage(void)
366367
printf(_(" -v, --verbose output verbose messages\n"));
367368
printf(_(" -V, --version output version information, then exit\n"));
368369
printf(_(" --no-slot prevent creation of temporary replication slot\n"));
370+
printf(_(" --snapshot=SNAPID snapfs snapshot\n"));
369371
printf(_(" --no-verify-checksums\n"
370372
" do not verify checksums\n"));
371373
printf(_(" -?, --help show this help, then exit\n"));
@@ -1814,15 +1816,17 @@ BaseBackup(void)
18141816
}
18151817

18161818
basebkp =
1817-
psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
1819+
psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s %s %s",
18181820
escaped_label,
18191821
showprogress ? "PROGRESS" : "",
18201822
includewal == FETCH_WAL ? "WAL" : "",
18211823
fastcheckpoint ? "FAST" : "",
18221824
includewal == NO_WAL ? "" : "NOWAIT",
18231825
maxrate_clause ? maxrate_clause : "",
18241826
format == 't' ? "TABLESPACE_MAP" : "",
1825-
verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
1827+
verify_checksums ? "" : "NOVERIFY_CHECKSUMS",
1828+
snapshot ? "SNAPSHOT" : "",
1829+
snapshot ? snapshot : "");
18261830

18271831
if (PQsendQuery(conn, basebkp) == 0)
18281832
{
@@ -2163,6 +2167,7 @@ main(int argc, char **argv)
21632167
{"waldir", required_argument, NULL, 1},
21642168
{"no-slot", no_argument, NULL, 2},
21652169
{"no-verify-checksums", no_argument, NULL, 3},
2170+
{"snapshot", required_argument, NULL, 4},
21662171
{NULL, 0, NULL, 0}
21672172
};
21682173
int c;
@@ -2334,6 +2339,9 @@ main(int argc, char **argv)
23342339
case 3:
23352340
verify_checksums = false;
23362341
break;
2342+
case 4:
2343+
snapshot = pg_strdup(optarg);
2344+
break;
23372345
default:
23382346

23392347
/*

src/include/storage/fd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ extern void AtEOXact_Files(bool isCommit);
126126
extern void AtEOSubXact_Files(bool isCommit, SubTransactionId mySubid,
127127
SubTransactionId parentSubid);
128128
extern void RemovePgTempFiles(void);
129+
extern bool is_snapfs_file(const char *name);
129130
extern bool looks_like_temp_rel_name(const char *name);
130131

131132
extern int pg_fsync(int fd);

src/include/storage/snapfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ typedef struct SnapshotMap
7474

7575
extern SnapshotId sfs_backend_snapshot;
7676
extern SnapshotId sfs_active_snapshot;
77+
extern bool sfs_basebackup;
7778

7879
/* Memory mapping function */
7980
extern int sfs_munmap(SnapshotMap * map);

0 commit comments

Comments
 (0)