Skip to content

Commit 0d9e0d9

Browse files
committed
Copy fsync() defines into test_fsync.c, someday place them in an
include. Propery align for O_DIRECT. Check for write()/fsync() failures.
1 parent f14d43d commit 0d9e0d9

File tree

1 file changed

+136
-41
lines changed

1 file changed

+136
-41
lines changed

src/tools/fsync/test_fsync.c

Lines changed: 136 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
/*
22
* test_fsync.c
3-
* tests if fsync can be done from another process than the original write
3+
* test various fsync() methods
44
*/
55

6-
#include "../../include/pg_config.h"
7-
#include "../../include/pg_config_os.h"
6+
#include "postgres.h"
7+
8+
#include "access/xlog_internal.h"
9+
#include "access/xlog.h"
810

911
#include <sys/types.h>
1012
#include <sys/stat.h>
@@ -14,29 +16,94 @@
1416
#include <time.h>
1517
#include <sys/time.h>
1618
#include <unistd.h>
19+
#include <string.h>
1720

18-
#ifdef WIN32
19-
#define FSYNC_FILENAME "./test_fsync.out"
21+
/* ---------------------------------------------------------------
22+
* Copied from xlog.c. Some day this should be moved an include file.
23+
*/
24+
25+
/*
26+
* Because O_DIRECT bypasses the kernel buffers, and because we never
27+
* read those buffers except during crash recovery, it is a win to use
28+
* it in all cases where we sync on each write(). We could allow O_DIRECT
29+
* with fsync(), but because skipping the kernel buffer forces writes out
30+
* quickly, it seems best just to use it for O_SYNC. It is hard to imagine
31+
* how fsync() could be a win for O_DIRECT compared to O_SYNC and O_DIRECT.
32+
* Also, O_DIRECT is never enough to force data to the drives, it merely
33+
* tries to bypass the kernel cache, so we still need O_SYNC or fsync().
34+
*/
35+
#ifdef O_DIRECT
36+
#define PG_O_DIRECT O_DIRECT
2037
#else
21-
#define FSYNC_FILENAME "/var/tmp/test_fsync.out"
38+
#define PG_O_DIRECT 0
2239
#endif
2340

24-
/* O_SYNC and O_FSYNC are the same */
41+
/*
42+
* This chunk of hackery attempts to determine which file sync methods
43+
* are available on the current platform, and to choose an appropriate
44+
* default method. We assume that fsync() is always available, and that
45+
* configure determined whether fdatasync() is.
46+
*/
2547
#if defined(O_SYNC)
26-
#define OPEN_SYNC_FLAG O_SYNC
48+
#define BARE_OPEN_SYNC_FLAG O_SYNC
2749
#elif defined(O_FSYNC)
28-
#define OPEN_SYNC_FLAG O_FSYNC
29-
#elif defined(O_DSYNC)
30-
#define OPEN_DATASYNC_FLAG O_DSYNC
50+
#define BARE_OPEN_SYNC_FLAG O_FSYNC
51+
#endif
52+
#ifdef BARE_OPEN_SYNC_FLAG
53+
#define OPEN_SYNC_FLAG (BARE_OPEN_SYNC_FLAG | PG_O_DIRECT)
3154
#endif
3255

56+
#if defined(O_DSYNC)
3357
#if defined(OPEN_SYNC_FLAG)
34-
#if defined(O_DSYNC) && (O_DSYNC != OPEN_SYNC_FLAG)
35-
#define OPEN_DATASYNC_FLAG O_DSYNC
58+
/* O_DSYNC is distinct? */
59+
#if O_DSYNC != BARE_OPEN_SYNC_FLAG
60+
#define OPEN_DATASYNC_FLAG (O_DSYNC | PG_O_DIRECT)
61+
#endif
62+
#else /* !defined(OPEN_SYNC_FLAG) */
63+
/* Win32 only has O_DSYNC */
64+
#define OPEN_DATASYNC_FLAG (O_DSYNC | PG_O_DIRECT)
65+
#endif
66+
#endif
67+
68+
#if defined(OPEN_DATASYNC_FLAG)
69+
#define DEFAULT_SYNC_METHOD_STR "open_datasync"
70+
#define DEFAULT_SYNC_METHOD SYNC_METHOD_OPEN
71+
#define DEFAULT_SYNC_FLAGBIT OPEN_DATASYNC_FLAG
72+
#elif defined(HAVE_FDATASYNC)
73+
#define DEFAULT_SYNC_METHOD_STR "fdatasync"
74+
#define DEFAULT_SYNC_METHOD SYNC_METHOD_FDATASYNC
75+
#define DEFAULT_SYNC_FLAGBIT 0
76+
#elif defined(HAVE_FSYNC_WRITETHROUGH_ONLY)
77+
#define DEFAULT_SYNC_METHOD_STR "fsync_writethrough"
78+
#define DEFAULT_SYNC_METHOD SYNC_METHOD_FSYNC_WRITETHROUGH
79+
#define DEFAULT_SYNC_FLAGBIT 0
80+
#else
81+
#define DEFAULT_SYNC_METHOD_STR "fsync"
82+
#define DEFAULT_SYNC_METHOD SYNC_METHOD_FSYNC
83+
#define DEFAULT_SYNC_FLAGBIT 0
84+
#endif
85+
86+
87+
/*
88+
* Limitation of buffer-alignment for direct IO depends on OS and filesystem,
89+
* but XLOG_BLCKSZ is assumed to be enough for it.
90+
*/
91+
#ifdef O_DIRECT
92+
#define ALIGNOF_XLOG_BUFFER XLOG_BLCKSZ
93+
#else
94+
#define ALIGNOF_XLOG_BUFFER ALIGNOF_BUFFER
3695
#endif
96+
97+
/* ------------ from xlog.c --------------- */
98+
99+
#ifdef WIN32
100+
#define FSYNC_FILENAME "./test_fsync.out"
101+
#else
102+
/* /tmp might be a memory file system */
103+
#define FSYNC_FILENAME "/var/tmp/test_fsync.out"
37104
#endif
38105

39-
#define WAL_FILE_SIZE (16 * 1024 * 1024)
106+
#define WRITE_SIZE (16 * 1024)
40107

41108
void die(char *str);
42109
void print_elapse(struct timeval start_t, struct timeval elapse_t);
@@ -49,7 +116,7 @@ main(int argc, char *argv[])
49116
int tmpfile,
50117
i,
51118
loops = 1000;
52-
char *strout = (char *) malloc(WAL_FILE_SIZE);
119+
char *full_buf = (char *) malloc(XLOG_SEG_SIZE), *buf;
53120
char *filename = FSYNC_FILENAME;
54121

55122
if (argc > 2 && strcmp(argv[1], "-f") == 0)
@@ -62,23 +129,29 @@ main(int argc, char *argv[])
62129
if (argc > 1)
63130
loops = atoi(argv[1]);
64131

65-
for (i = 0; i < WAL_FILE_SIZE; i++)
66-
strout[i] = 'a';
132+
for (i = 0; i < XLOG_SEG_SIZE; i++)
133+
full_buf[i] = 'a';
67134

68135
if ((tmpfile = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1)
69136
die("Cannot open output file.");
70-
write(tmpfile, strout, WAL_FILE_SIZE);
71-
fsync(tmpfile); /* fsync so later fsync's don't have to do it */
137+
if (write(tmpfile, full_buf, XLOG_SEG_SIZE) != XLOG_SEG_SIZE)
138+
die("write failed");
139+
/* fsync so later fsync's don't have to do it */
140+
if (fsync(tmpfile) != 0)
141+
die("fsync failed");
72142
close(tmpfile);
73143

144+
buf = (char *)TYPEALIGN(ALIGNOF_XLOG_BUFFER, full_buf);
145+
74146
printf("Simple write timing:\n");
75147
/* write only */
76148
gettimeofday(&start_t, NULL);
77149
for (i = 0; i < loops; i++)
78150
{
79151
if ((tmpfile = open(filename, O_RDWR)) == -1)
80152
die("Cannot open output file.");
81-
write(tmpfile, strout, 8192);
153+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
154+
die("write failed");
82155
close(tmpfile);
83156
}
84157
gettimeofday(&elapse_t, NULL);
@@ -95,8 +168,10 @@ main(int argc, char *argv[])
95168
{
96169
if ((tmpfile = open(filename, O_RDWR)) == -1)
97170
die("Cannot open output file.");
98-
write(tmpfile, strout, 8192);
99-
fsync(tmpfile);
171+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
172+
die("write failed");
173+
if (fsync(tmpfile) != 0)
174+
die("fsync failed");
100175
close(tmpfile);
101176
if ((tmpfile = open(filename, O_RDWR)) == -1)
102177
die("Cannot open output file.");
@@ -114,12 +189,14 @@ main(int argc, char *argv[])
114189
{
115190
if ((tmpfile = open(filename, O_RDWR)) == -1)
116191
die("Cannot open output file.");
117-
write(tmpfile, strout, 8192);
192+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
193+
die("write failed");
118194
close(tmpfile);
119195
/* reopen file */
120196
if ((tmpfile = open(filename, O_RDWR)) == -1)
121197
die("Cannot open output file.");
122-
fsync(tmpfile);
198+
if (fsync(tmpfile) != 0)
199+
die("fsync failed");
123200
close(tmpfile);
124201
}
125202
gettimeofday(&elapse_t, NULL);
@@ -135,7 +212,8 @@ main(int argc, char *argv[])
135212
die("Cannot open output file.");
136213
gettimeofday(&start_t, NULL);
137214
for (i = 0; i < loops; i++)
138-
write(tmpfile, strout, 16384);
215+
if (write(tmpfile, buf, WRITE_SIZE) != WRITE_SIZE)
216+
die("write failed");
139217
gettimeofday(&elapse_t, NULL);
140218
close(tmpfile);
141219
printf("\tone 16k o_sync write ");
@@ -148,8 +226,10 @@ main(int argc, char *argv[])
148226
gettimeofday(&start_t, NULL);
149227
for (i = 0; i < loops; i++)
150228
{
151-
write(tmpfile, strout, 8192);
152-
write(tmpfile, strout, 8192);
229+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
230+
die("write failed");
231+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
232+
die("write failed");
153233
}
154234
gettimeofday(&elapse_t, NULL);
155235
close(tmpfile);
@@ -169,7 +249,8 @@ main(int argc, char *argv[])
169249
die("Cannot open output file.");
170250
gettimeofday(&start_t, NULL);
171251
for (i = 0; i < loops; i++)
172-
write(tmpfile, strout, 8192);
252+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
253+
die("write failed");
173254
gettimeofday(&elapse_t, NULL);
174255
close(tmpfile);
175256
printf("\topen o_dsync, write ");
@@ -181,7 +262,8 @@ main(int argc, char *argv[])
181262
die("Cannot open output file.");
182263
gettimeofday(&start_t, NULL);
183264
for (i = 0; i < loops; i++)
184-
write(tmpfile, strout, 8192);
265+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
266+
die("write failed");
185267
gettimeofday(&elapse_t, NULL);
186268
close(tmpfile);
187269
printf("\topen o_sync, write ");
@@ -199,7 +281,8 @@ main(int argc, char *argv[])
199281
gettimeofday(&start_t, NULL);
200282
for (i = 0; i < loops; i++)
201283
{
202-
write(tmpfile, strout, 8192);
284+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
285+
die("write failed");
203286
fdatasync(tmpfile);
204287
}
205288
gettimeofday(&elapse_t, NULL);
@@ -217,8 +300,10 @@ main(int argc, char *argv[])
217300
gettimeofday(&start_t, NULL);
218301
for (i = 0; i < loops; i++)
219302
{
220-
write(tmpfile, strout, 8192);
221-
fsync(tmpfile);
303+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
304+
die("write failed");
305+
if (fsync(tmpfile) != 0)
306+
die("fsync failed");
222307
}
223308
gettimeofday(&elapse_t, NULL);
224309
close(tmpfile);
@@ -235,8 +320,10 @@ main(int argc, char *argv[])
235320
gettimeofday(&start_t, NULL);
236321
for (i = 0; i < loops; i++)
237322
{
238-
write(tmpfile, strout, 8192);
239-
write(tmpfile, strout, 8192);
323+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
324+
die("write failed");
325+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
326+
die("write failed");
240327
}
241328
gettimeofday(&elapse_t, NULL);
242329
close(tmpfile);
@@ -254,8 +341,10 @@ main(int argc, char *argv[])
254341
gettimeofday(&start_t, NULL);
255342
for (i = 0; i < loops; i++)
256343
{
257-
write(tmpfile, strout, 8192);
258-
write(tmpfile, strout, 8192);
344+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
345+
die("write failed");
346+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
347+
die("write failed");
259348
}
260349
gettimeofday(&elapse_t, NULL);
261350
close(tmpfile);
@@ -271,8 +360,10 @@ main(int argc, char *argv[])
271360
gettimeofday(&start_t, NULL);
272361
for (i = 0; i < loops; i++)
273362
{
274-
write(tmpfile, strout, 8192);
275-
write(tmpfile, strout, 8192);
363+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
364+
die("write failed");
365+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
366+
die("write failed");
276367
fdatasync(tmpfile);
277368
}
278369
gettimeofday(&elapse_t, NULL);
@@ -290,16 +381,20 @@ main(int argc, char *argv[])
290381
gettimeofday(&start_t, NULL);
291382
for (i = 0; i < loops; i++)
292383
{
293-
write(tmpfile, strout, 8192);
294-
write(tmpfile, strout, 8192);
295-
fsync(tmpfile);
384+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
385+
die("write failed");
386+
if (write(tmpfile, buf, WRITE_SIZE/2) != WRITE_SIZE/2)
387+
die("write failed");
388+
if (fsync(tmpfile) != 0)
389+
die("fsync failed");
296390
}
297391
gettimeofday(&elapse_t, NULL);
298392
close(tmpfile);
299393
printf("\twrite, fsync, ");
300394
print_elapse(start_t, elapse_t);
301395
printf("\n");
302396

397+
free(full_buf);
303398
unlink(filename);
304399

305400
return 0;

0 commit comments

Comments
 (0)