Skip to content

Commit d694e0b

Browse files
committed
Add pg_file_sync() to adminpack extension.
This function allows us to fsync the specified file or directory. It's useful, for example, when we want to sync the file that pg_file_write() writes out or that COPY TO exports the data into, for durability. Author: Fujii Masao Reviewed-By: Julien Rouhaud, Arthur Zakirov, Michael Paquier, Atsushi Torikoshi Discussion: https://www.postgresql.org/message-id/CAHGQGwGY8uzZ_k8dHRoW1zDcy1Z7=5GQ+So4ZkVy2u=nLsk=hA@mail.gmail.com
1 parent cc25464 commit d694e0b

File tree

9 files changed

+89
-4
lines changed

9 files changed

+89
-4
lines changed

contrib/adminpack/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ OBJS = \
77
PG_CPPFLAGS = -I$(libpq_srcdir)
88

99
EXTENSION = adminpack
10-
DATA = adminpack--1.0.sql adminpack--1.0--1.1.sql adminpack--1.1--2.0.sql
10+
DATA = adminpack--1.0.sql adminpack--1.0--1.1.sql adminpack--1.1--2.0.sql\
11+
adminpack--2.0--2.1.sql
1112
PGFILEDESC = "adminpack - support functions for pgAdmin"
1213

1314
REGRESS = adminpack
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* contrib/adminpack/adminpack--2.0--2.1.sql */
2+
3+
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
4+
\echo Use "ALTER EXTENSION adminpack UPDATE TO '2.1'" to load this file. \quit
5+
6+
/* ***********************************************
7+
* Administrative functions for PostgreSQL
8+
* *********************************************** */
9+
10+
/* generic file access functions */
11+
12+
CREATE OR REPLACE FUNCTION pg_catalog.pg_file_sync(text)
13+
RETURNS void
14+
AS 'MODULE_PATHNAME', 'pg_file_sync'
15+
LANGUAGE C VOLATILE STRICT;
16+
17+
REVOKE EXECUTE ON FUNCTION pg_catalog.pg_file_sync(text) FROM PUBLIC;

contrib/adminpack/adminpack.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ PG_MODULE_MAGIC;
4343

4444
PG_FUNCTION_INFO_V1(pg_file_write);
4545
PG_FUNCTION_INFO_V1(pg_file_write_v1_1);
46+
PG_FUNCTION_INFO_V1(pg_file_sync);
4647
PG_FUNCTION_INFO_V1(pg_file_rename);
4748
PG_FUNCTION_INFO_V1(pg_file_rename_v1_1);
4849
PG_FUNCTION_INFO_V1(pg_file_unlink);
@@ -215,6 +216,30 @@ pg_file_write_internal(text *file, text *data, bool replace)
215216
return (count);
216217
}
217218

219+
/* ------------------------------------
220+
* pg_file_sync
221+
*
222+
* We REVOKE EXECUTE on the function from PUBLIC.
223+
* Users can then grant access to it based on their policies.
224+
*/
225+
Datum
226+
pg_file_sync(PG_FUNCTION_ARGS)
227+
{
228+
char *filename;
229+
struct stat fst;
230+
231+
filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0), false);
232+
233+
if (stat(filename, &fst) < 0)
234+
ereport(ERROR,
235+
(errcode_for_file_access(),
236+
errmsg("could not stat file \"%s\": %m", filename)));
237+
238+
fsync_fname_ext(filename, S_ISDIR(fst.st_mode), false, ERROR);
239+
240+
PG_RETURN_VOID();
241+
}
242+
218243
/* ------------------------------------
219244
* pg_file_rename - old version
220245
*

contrib/adminpack/adminpack.control

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# adminpack extension
22
comment = 'administrative functions for PostgreSQL'
3-
default_version = '2.0'
3+
default_version = '2.1'
44
module_pathname = '$libdir/adminpack'
55
relocatable = false
66
schema = pg_catalog

contrib/adminpack/expected/adminpack.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,21 @@ RESET ROLE;
5656
REVOKE EXECUTE ON FUNCTION pg_file_write(text,text,bool) FROM regress_user1;
5757
REVOKE pg_read_all_settings FROM regress_user1;
5858
DROP ROLE regress_user1;
59+
-- sync
60+
SELECT pg_file_sync('test_file1'); -- sync file
61+
pg_file_sync
62+
--------------
63+
64+
(1 row)
65+
66+
SELECT pg_file_sync('pg_stat'); -- sync directory
67+
pg_file_sync
68+
--------------
69+
70+
(1 row)
71+
72+
SELECT pg_file_sync('test_file2'); -- not there
73+
ERROR: could not stat file "test_file2": No such file or directory
5974
-- rename file
6075
SELECT pg_file_rename('test_file1', 'test_file2');
6176
pg_file_rename
@@ -142,6 +157,8 @@ CREATE USER regress_user1;
142157
SET ROLE regress_user1;
143158
SELECT pg_file_write('test_file0', 'test0', false);
144159
ERROR: permission denied for function pg_file_write
160+
SELECT pg_file_sync('test_file0');
161+
ERROR: permission denied for function pg_file_sync
145162
SELECT pg_file_rename('test_file0', 'test_file0');
146163
ERROR: permission denied for function pg_file_rename
147164
CONTEXT: SQL function "pg_file_rename" statement 1

contrib/adminpack/sql/adminpack.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ REVOKE EXECUTE ON FUNCTION pg_file_write(text,text,bool) FROM regress_user1;
2929
REVOKE pg_read_all_settings FROM regress_user1;
3030
DROP ROLE regress_user1;
3131

32+
-- sync
33+
SELECT pg_file_sync('test_file1'); -- sync file
34+
SELECT pg_file_sync('pg_stat'); -- sync directory
35+
SELECT pg_file_sync('test_file2'); -- not there
36+
3237
-- rename file
3338
SELECT pg_file_rename('test_file1', 'test_file2');
3439
SELECT pg_read_file('test_file1'); -- not there
@@ -58,6 +63,7 @@ CREATE USER regress_user1;
5863
SET ROLE regress_user1;
5964

6065
SELECT pg_file_write('test_file0', 'test0', false);
66+
SELECT pg_file_sync('test_file0');
6167
SELECT pg_file_rename('test_file0', 'test_file0');
6268
SELECT pg_file_unlink('test_file0');
6369
SELECT pg_logdir_ls();

doc/src/sgml/adminpack.sgml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@
4343
Write, or append to, a text file
4444
</entry>
4545
</row>
46+
<row>
47+
<entry><function>pg_catalog.pg_file_sync(filename text)</function></entry>
48+
<entry><type>void</type></entry>
49+
<entry>
50+
Flush a file or directory to disk
51+
</entry>
52+
</row>
4653
<row>
4754
<entry><function>pg_catalog.pg_file_rename(oldname text, newname text <optional>, archivename text</optional>)</function></entry>
4855
<entry><type>boolean</type></entry>
@@ -79,6 +86,18 @@
7986
Returns the number of bytes written.
8087
</para>
8188

89+
<indexterm>
90+
<primary>pg_file_sync</primary>
91+
</indexterm>
92+
<para>
93+
<function>pg_file_sync</function> fsyncs the specified file or directory
94+
named by <parameter>filename</parameter>. An error is thrown
95+
on failure (e.g., the specified file is not present). Note that
96+
<xref linkend="guc-data-sync-retry"/> has no effect on this function,
97+
and therefore a PANIC-level error will not be raised even on failure to
98+
flush database files.
99+
</para>
100+
82101
<indexterm>
83102
<primary>pg_file_rename</primary>
84103
</indexterm>

src/backend/storage/file/fd.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,6 @@ static void pre_sync_fname(const char *fname, bool isdir, int elevel);
319319
static void datadir_fsync_fname(const char *fname, bool isdir, int elevel);
320320
static void unlink_if_exists_fname(const char *fname, bool isdir, int elevel);
321321

322-
static int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel);
323322
static int fsync_parent_path(const char *fname, int elevel);
324323

325324

@@ -3376,7 +3375,7 @@ unlink_if_exists_fname(const char *fname, bool isdir, int elevel)
33763375
*
33773376
* Returns 0 if the operation succeeded, -1 otherwise.
33783377
*/
3379-
static int
3378+
int
33803379
fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel)
33813380
{
33823381
int fd;

src/include/storage/fd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ extern int pg_fsync_writethrough(int fd);
145145
extern int pg_fdatasync(int fd);
146146
extern void pg_flush_data(int fd, off_t offset, off_t amount);
147147
extern void fsync_fname(const char *fname, bool isdir);
148+
extern int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel);
148149
extern int durable_rename(const char *oldfile, const char *newfile, int loglevel);
149150
extern int durable_unlink(const char *fname, int loglevel);
150151
extern int durable_link_or_rename(const char *oldfile, const char *newfile, int loglevel);

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