nbtree: fix read page recheck typo.
[pgsql.git] / src / backend / backup / basebackup_server.c
blobf5c0c61640a9416895d7d85aee4b1c8a02c6e345
1 /*-------------------------------------------------------------------------
3 * basebackup_server.c
4 * store basebackup archives on the server
6 * IDENTIFICATION
7 * src/backend/backup/basebackup_server.c
9 *-------------------------------------------------------------------------
11 #include "postgres.h"
13 #include "access/xact.h"
14 #include "backup/basebackup_sink.h"
15 #include "catalog/pg_authid.h"
16 #include "miscadmin.h"
17 #include "storage/fd.h"
18 #include "utils/acl.h"
19 #include "utils/wait_event.h"
21 typedef struct bbsink_server
23 /* Common information for all types of sink. */
24 bbsink base;
26 /* Directory in which backup is to be stored. */
27 char *pathname;
29 /* Currently open file (or 0 if nothing open). */
30 File file;
32 /* Current file position. */
33 off_t filepos;
34 } bbsink_server;
36 static void bbsink_server_begin_archive(bbsink *sink,
37 const char *archive_name);
38 static void bbsink_server_archive_contents(bbsink *sink, size_t len);
39 static void bbsink_server_end_archive(bbsink *sink);
40 static void bbsink_server_begin_manifest(bbsink *sink);
41 static void bbsink_server_manifest_contents(bbsink *sink, size_t len);
42 static void bbsink_server_end_manifest(bbsink *sink);
44 static const bbsink_ops bbsink_server_ops = {
45 .begin_backup = bbsink_forward_begin_backup,
46 .begin_archive = bbsink_server_begin_archive,
47 .archive_contents = bbsink_server_archive_contents,
48 .end_archive = bbsink_server_end_archive,
49 .begin_manifest = bbsink_server_begin_manifest,
50 .manifest_contents = bbsink_server_manifest_contents,
51 .end_manifest = bbsink_server_end_manifest,
52 .end_backup = bbsink_forward_end_backup,
53 .cleanup = bbsink_forward_cleanup
57 * Create a new 'server' bbsink.
59 bbsink *
60 bbsink_server_new(bbsink *next, char *pathname)
62 bbsink_server *sink = palloc0(sizeof(bbsink_server));
64 *((const bbsink_ops **) &sink->base.bbs_ops) = &bbsink_server_ops;
65 sink->pathname = pathname;
66 sink->base.bbs_next = next;
68 /* Replication permission is not sufficient in this case. */
69 StartTransactionCommand();
70 if (!has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
71 ereport(ERROR,
72 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
73 errmsg("permission denied to create backup stored on server"),
74 errdetail("Only roles with privileges of the \"%s\" role may create a backup stored on the server.",
75 "pg_write_server_files")));
76 CommitTransactionCommand();
79 * It's not a good idea to store your backups in the same directory that
80 * you're backing up. If we allowed a relative path here, that could
81 * easily happen accidentally, so we don't. The user could still
82 * accomplish the same thing by including the absolute path to $PGDATA in
83 * the pathname, but that's likely an intentional bad decision rather than
84 * an accident.
86 if (!is_absolute_path(pathname))
87 ereport(ERROR,
88 (errcode(ERRCODE_INVALID_NAME),
89 errmsg("relative path not allowed for backup stored on server")));
91 switch (pg_check_dir(pathname))
93 case 0:
96 * Does not exist, so create it using the same permissions we'd
97 * use for a new subdirectory of the data directory itself.
99 if (MakePGDirectory(pathname) < 0)
100 ereport(ERROR,
101 (errcode_for_file_access(),
102 errmsg("could not create directory \"%s\": %m", pathname)));
103 break;
105 case 1:
106 /* Exists, empty. */
107 break;
109 case 2:
110 case 3:
111 case 4:
112 /* Exists, not empty. */
113 ereport(ERROR,
114 (errcode(ERRCODE_DUPLICATE_FILE),
115 errmsg("directory \"%s\" exists but is not empty",
116 pathname)));
117 break;
119 default:
120 /* Access problem. */
121 ereport(ERROR,
122 (errcode_for_file_access(),
123 errmsg("could not access directory \"%s\": %m",
124 pathname)));
127 return &sink->base;
131 * Open the correct output file for this archive.
133 static void
134 bbsink_server_begin_archive(bbsink *sink, const char *archive_name)
136 bbsink_server *mysink = (bbsink_server *) sink;
137 char *filename;
139 Assert(mysink->file == 0);
140 Assert(mysink->filepos == 0);
142 filename = psprintf("%s/%s", mysink->pathname, archive_name);
144 mysink->file = PathNameOpenFile(filename,
145 O_CREAT | O_EXCL | O_WRONLY | PG_BINARY);
146 if (mysink->file <= 0)
147 ereport(ERROR,
148 (errcode_for_file_access(),
149 errmsg("could not create file \"%s\": %m", filename)));
151 pfree(filename);
153 bbsink_forward_begin_archive(sink, archive_name);
157 * Write the data to the output file.
159 static void
160 bbsink_server_archive_contents(bbsink *sink, size_t len)
162 bbsink_server *mysink = (bbsink_server *) sink;
163 int nbytes;
165 nbytes = FileWrite(mysink->file, mysink->base.bbs_buffer, len,
166 mysink->filepos, WAIT_EVENT_BASEBACKUP_WRITE);
168 if (nbytes != len)
170 if (nbytes < 0)
171 ereport(ERROR,
172 (errcode_for_file_access(),
173 errmsg("could not write file \"%s\": %m",
174 FilePathName(mysink->file)),
175 errhint("Check free disk space.")));
176 /* short write: complain appropriately */
177 ereport(ERROR,
178 (errcode(ERRCODE_DISK_FULL),
179 errmsg("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
180 FilePathName(mysink->file),
181 nbytes, (int) len, (unsigned) mysink->filepos),
182 errhint("Check free disk space.")));
185 mysink->filepos += nbytes;
187 bbsink_forward_archive_contents(sink, len);
191 * fsync and close the current output file.
193 static void
194 bbsink_server_end_archive(bbsink *sink)
196 bbsink_server *mysink = (bbsink_server *) sink;
199 * We intentionally don't use data_sync_elevel here, because the server
200 * shouldn't PANIC just because we can't guarantee that the backup has
201 * been written down to disk. Running recovery won't fix anything in this
202 * case anyway.
204 if (FileSync(mysink->file, WAIT_EVENT_BASEBACKUP_SYNC) < 0)
205 ereport(ERROR,
206 (errcode_for_file_access(),
207 errmsg("could not fsync file \"%s\": %m",
208 FilePathName(mysink->file))));
211 /* We're done with this file now. */
212 FileClose(mysink->file);
213 mysink->file = 0;
214 mysink->filepos = 0;
216 bbsink_forward_end_archive(sink);
220 * Open the output file to which we will write the manifest.
222 * Just like pg_basebackup, we write the manifest first under a temporary
223 * name and then rename it into place after fsync. That way, if the manifest
224 * is there and under the correct name, the user can be sure that the backup
225 * completed.
227 static void
228 bbsink_server_begin_manifest(bbsink *sink)
230 bbsink_server *mysink = (bbsink_server *) sink;
231 char *tmp_filename;
233 Assert(mysink->file == 0);
235 tmp_filename = psprintf("%s/backup_manifest.tmp", mysink->pathname);
237 mysink->file = PathNameOpenFile(tmp_filename,
238 O_CREAT | O_EXCL | O_WRONLY | PG_BINARY);
239 if (mysink->file <= 0)
240 ereport(ERROR,
241 (errcode_for_file_access(),
242 errmsg("could not create file \"%s\": %m", tmp_filename)));
244 pfree(tmp_filename);
246 bbsink_forward_begin_manifest(sink);
250 * Each chunk of manifest data is sent using a CopyData message.
252 static void
253 bbsink_server_manifest_contents(bbsink *sink, size_t len)
255 bbsink_server *mysink = (bbsink_server *) sink;
256 int nbytes;
258 nbytes = FileWrite(mysink->file, mysink->base.bbs_buffer, len,
259 mysink->filepos, WAIT_EVENT_BASEBACKUP_WRITE);
261 if (nbytes != len)
263 if (nbytes < 0)
264 ereport(ERROR,
265 (errcode_for_file_access(),
266 errmsg("could not write file \"%s\": %m",
267 FilePathName(mysink->file)),
268 errhint("Check free disk space.")));
269 /* short write: complain appropriately */
270 ereport(ERROR,
271 (errcode(ERRCODE_DISK_FULL),
272 errmsg("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
273 FilePathName(mysink->file),
274 nbytes, (int) len, (unsigned) mysink->filepos),
275 errhint("Check free disk space.")));
278 mysink->filepos += nbytes;
280 bbsink_forward_manifest_contents(sink, len);
284 * fsync the backup manifest, close the file, and then rename it into place.
286 static void
287 bbsink_server_end_manifest(bbsink *sink)
289 bbsink_server *mysink = (bbsink_server *) sink;
290 char *tmp_filename;
291 char *filename;
293 /* We're done with this file now. */
294 FileClose(mysink->file);
295 mysink->file = 0;
298 * Rename it into place. This also fsyncs the temporary file, so we don't
299 * need to do that here. We don't use data_sync_elevel here for the same
300 * reasons as in bbsink_server_end_archive.
302 tmp_filename = psprintf("%s/backup_manifest.tmp", mysink->pathname);
303 filename = psprintf("%s/backup_manifest", mysink->pathname);
304 durable_rename(tmp_filename, filename, ERROR);
305 pfree(filename);
306 pfree(tmp_filename);
308 bbsink_forward_end_manifest(sink);