-
Notifications
You must be signed in to change notification settings - Fork 5
/
pgespresso.c
207 lines (177 loc) · 5.82 KB
/
pgespresso.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*-------------------------------------------------------------------------
*
* pgespresso.c
*
*
* Copyright (c) 2014, 2ndQuadrant Limited <www.2ndquadrant.com>
*
* Authors: Simon Riggs <[email protected]>
* Marco Nenciarini <[email protected]>
* Gabriele Bartolini <[email protected]>
*
* See COPYING for licensing information
*
* IDENTIFICATION
* pgespresso/pgespresso.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/xlog.h"
#include "access/xlog_internal.h"
#include "access/xlogdefs.h"
#include "utils/builtins.h"
#include "miscadmin.h"
PG_MODULE_MAGIC;
Datum pgespresso_start_backup(PG_FUNCTION_ARGS);
Datum pgespresso_stop_backup(PG_FUNCTION_ARGS);
Datum pgespresso_abort_backup(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(pgespresso_start_backup);
PG_FUNCTION_INFO_V1(pgespresso_stop_backup);
PG_FUNCTION_INFO_V1(pgespresso_abort_backup);
/*
* pgespresso_start_backup: set up for taking an on-line backup dump
*
* Essentially what this does is to return a backup label file that the
* user is responsible for placing in the $PGDATA of the backup AFTER
* the backup has been taken. The label file must not be written to the
* data directory of the server from which the backup is taken because
* this type of backup presumes and allows that more than one backup
* may be in progress at any one time. The label file
* contains the user-supplied label string (typically this would be used
* to tell where the backup dump will be stored) and the starting time and
* starting WAL location for the dump.
*/
Datum
pgespresso_start_backup(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_P(0);
bool fast = PG_GETARG_BOOL(1);
char *backupidstr;
char *labelfile;
backupidstr = text_to_cstring(backupid);
if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser or replication role to run a backup")));
/*
* ThisTimeLineID is always 0 in a normal backend during recovery.
* We get latest redo apply position timeline and we update it globally
* to make do_pg_start_backup use the correct value when generating
* the backup label text
*/
if (RecoveryInProgress()) {
TimeLineID replayTLI;
GetXLogReplayRecPtr(&replayTLI);
ThisTimeLineID = replayTLI;
elog(DEBUG1, "updated ThisTimeLineID = %u", ThisTimeLineID);
}
/*
* Starting from 9.5 the do_pg_start_backup caller needs to allocate the
* 'pg_tblspc' directory and pass it as argument.
*
* Ref: http://git.postgresql.org/gitweb/?p=postgresql.git;h=72d422a
*/
#if PG_VERSION_NUM >= 90500
{
DIR *dir;
char *tblspcmapfile = NULL;
/* Make sure we can open the directory with
tablespaces in it */
dir = AllocateDir("pg_tblspc");
if (!dir)
ereport(ERROR,
(errmsg("could not open directory \"%s\": %m", "pg_tblspc")));
/*
* We are not filling the tablespace map here.
* This means that on 9.5 the 'tablespace_map' file has to be
* generated by the invoker.
*/
do_pg_start_backup(backupidstr, fast, NULL, &labelfile,
dir, NULL, &tblspcmapfile, false, false);
FreeDir(dir);
if (tblspcmapfile)
pfree(tblspcmapfile);
}
/*
* Starting from 9.3 the do_pg_start_backup returns the timeline ID
* in *starttli_p additional argument
*/
#elif PG_VERSION_NUM >= 90300
do_pg_start_backup(backupidstr, fast, NULL, &labelfile);
#else
do_pg_start_backup(backupidstr, fast, &labelfile);
#endif
PG_RETURN_TEXT_P(cstring_to_text(labelfile));
}
/*
* pgespresso_stop_backup: finish taking an on-line backup dump
*
* Only parameter is the labelfile returned from pg_start_concurrent_backup
*
* Return is the XLOG filename containing end of backup location, combining
* both the TLI and the end location. NOTE: the user is responsible for
* ensuring that the last file is correctly archived.
*/
Datum
pgespresso_stop_backup(PG_FUNCTION_ARGS)
{
XLogRecPtr stoppoint;
text *labelfile = PG_GETARG_TEXT_P(0);
char *backupidstr;
char xlogfilename[MAXFNAMELEN];
backupidstr = text_to_cstring(labelfile);
if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser or replication role to run a backup"))));
#if PG_VERSION_NUM >= 90300
{
XLogSegNo xlogsegno;
TimeLineID endtli;
stoppoint = do_pg_stop_backup(backupidstr,
false, /* don't wait for archive */
&endtli);
XLByteToPrevSeg(stoppoint, xlogsegno);
XLogFileName(xlogfilename, endtli, xlogsegno);
}
#else
{
uint32 xlogid;
uint32 xlogseg;
stoppoint = do_pg_stop_backup(backupidstr,
false); /* don't wait for archive */
/*
* In 9.2 the do_pg_stop_backup doesn't return the timeline ID and
* ThisTimeLineID is always 0 in a normal backend during recovery.
* We get latest redo apply position timeline and we update it globally
*/
if (RecoveryInProgress()) {
TimeLineID replayTLI;
GetXLogReplayRecPtr(&replayTLI);
ThisTimeLineID = replayTLI;
elog(DEBUG1, "updated ThisTimeLineID = %u", ThisTimeLineID);
}
XLByteToPrevSeg(stoppoint, xlogid, xlogseg);
XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg);
}
#endif
PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
}
/*
* pgespresso_abort_backup: abort a running backup
*
* This does just the most basic steps of pgespresso_stop_backup(), by taking
* the system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*/
Datum
pgespresso_abort_backup(PG_FUNCTION_ARGS)
{
if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser or replication role to run a backup"))));
do_pg_abort_backup();
PG_RETURN_VOID();
}