Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * pg_test_fsync --- tests all supported fsync() methods
4 : : *
5 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
6 : : *
7 : : * src/bin/pg_test_fsync/pg_test_fsync.c
8 : : *
9 : : *-------------------------------------------------------------------------
10 : : */
11 : :
12 : : #include "postgres_fe.h"
13 : :
14 : : #include <limits.h>
15 : : #include <sys/stat.h>
16 : : #include <sys/time.h>
17 : : #include <fcntl.h>
18 : : #include <time.h>
19 : : #include <unistd.h>
20 : : #include <signal.h>
21 : :
22 : : #include "common/logging.h"
23 : : #include "common/pg_prng.h"
24 : : #include "getopt_long.h"
25 : :
26 : : /*
27 : : * put the temp files in the local directory
28 : : * unless the user specifies otherwise
29 : : */
30 : : #define FSYNC_FILENAME "./pg_test_fsync.out"
31 : :
32 : : #define XLOG_BLCKSZ_K (XLOG_BLCKSZ / 1024)
33 : :
34 : : #define LABEL_FORMAT " %-30s"
35 : : #define NA_FORMAT "%21s\n"
36 : : /* translator: maintain alignment with NA_FORMAT */
37 : : #define OPS_FORMAT gettext_noop("%13.3f ops/sec %6.0f usecs/op\n")
38 : : #define USECS_SEC 1000000
39 : :
40 : : /* These are macros to avoid timing the function call overhead. */
41 : : #ifndef WIN32
42 : : #define START_TIMER \
43 : : do { \
44 : : alarm_triggered = false; \
45 : : alarm(secs_per_test); \
46 : : gettimeofday(&start_t, NULL); \
47 : : } while (0)
48 : : #else
49 : : /* WIN32 doesn't support alarm, so we create a thread and sleep there */
50 : : #define START_TIMER \
51 : : do { \
52 : : alarm_triggered = false; \
53 : : if (CreateThread(NULL, 0, process_alarm, NULL, 0, NULL) == \
54 : : INVALID_HANDLE_VALUE) \
55 : : pg_fatal("could not create thread for alarm"); \
56 : : gettimeofday(&start_t, NULL); \
57 : : } while (0)
58 : : #endif
59 : :
60 : : #define STOP_TIMER \
61 : : do { \
62 : : gettimeofday(&stop_t, NULL); \
63 : : print_elapse(start_t, stop_t, ops); \
64 : : } while (0)
65 : :
66 : :
67 : : static const char *progname;
68 : :
69 : : static unsigned int secs_per_test = 5;
70 : : static int needs_unlink = 0;
71 : : static char full_buf[DEFAULT_XLOG_SEG_SIZE],
72 : : *buf,
73 : : *filename = FSYNC_FILENAME;
74 : : static struct timeval start_t,
75 : : stop_t;
76 : : static sig_atomic_t alarm_triggered = false;
77 : :
78 : :
79 : : static void handle_args(int argc, char *argv[]);
80 : : static void prepare_buf(void);
81 : : static void test_open(void);
82 : : static void test_non_sync(void);
83 : : static void test_sync(int writes_per_op);
84 : : static void test_open_syncs(void);
85 : : static void test_open_sync(const char *msg, int writes_size);
86 : : static void test_file_descriptor_sync(void);
87 : :
88 : : #ifndef WIN32
89 : : static void process_alarm(SIGNAL_ARGS);
90 : : #else
91 : : static DWORD WINAPI process_alarm(LPVOID param);
92 : : #endif
93 : : static void signal_cleanup(SIGNAL_ARGS);
94 : :
95 : : #ifdef HAVE_FSYNC_WRITETHROUGH
96 : : static int pg_fsync_writethrough(int fd);
97 : : #endif
98 : : static void print_elapse(struct timeval start_t, struct timeval stop_t, int ops);
99 : :
100 : : #define die(msg) pg_fatal("%s: %m", _(msg))
101 : :
102 : :
103 : : int
7842 bruce@momjian.us 104 :CBC 5 : main(int argc, char *argv[])
105 : : {
2350 peter@eisentraut.org 106 : 5 : pg_logging_init(argv[0]);
3249 peter_e@gmx.net 107 : 5 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_fsync"));
5341 tgl@sss.pgh.pa.us 108 : 5 : progname = get_progname(argv[0]);
109 : :
5348 bruce@momjian.us 110 : 5 : handle_args(argc, argv);
111 : :
112 : : /* Prevent leaving behind the test file */
4556 tgl@sss.pgh.pa.us 113 :UBC 0 : pqsignal(SIGINT, signal_cleanup);
114 : 0 : pqsignal(SIGTERM, signal_cleanup);
115 : :
116 : : /* the following are not valid on Windows */
117 : : #ifndef WIN32
118 : 0 : pqsignal(SIGALRM, process_alarm);
119 : 0 : pqsignal(SIGHUP, signal_cleanup);
120 : : #endif
121 : :
1378 122 : 0 : pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
123 : :
5348 bruce@momjian.us 124 : 0 : prepare_buf();
125 : :
126 : 0 : test_open();
127 : :
128 : : /* Test using 1 XLOG_BLCKSZ write */
129 : 0 : test_sync(1);
130 : :
131 : : /* Test using 2 XLOG_BLCKSZ writes */
132 : 0 : test_sync(2);
133 : :
134 : 0 : test_open_syncs();
135 : :
136 : 0 : test_file_descriptor_sync();
137 : :
5345 138 : 0 : test_non_sync();
139 : :
5348 140 : 0 : unlink(filename);
141 : :
142 : 0 : return 0;
143 : : }
144 : :
145 : : static void
5348 bruce@momjian.us 146 :CBC 5 : handle_args(int argc, char *argv[])
147 : : {
148 : : static struct option long_options[] = {
149 : : {"filename", required_argument, NULL, 'f'},
150 : : {"secs-per-test", required_argument, NULL, 's'},
151 : : {NULL, 0, NULL, 0}
152 : : };
153 : :
154 : : int option; /* Command line option */
5346 155 : 5 : int optindex = 0; /* used by getopt_long */
156 : : unsigned long optval; /* used for option parsing */
157 : : char *endptr;
158 : :
159 [ + - ]: 5 : if (argc > 1)
160 : : {
4450 161 [ + + - + ]: 5 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
162 : : {
3249 peter_e@gmx.net 163 : 1 : printf(_("Usage: %s [-f FILENAME] [-s SECS-PER-TEST]\n"), progname);
5346 bruce@momjian.us 164 : 1 : exit(0);
165 : : }
166 [ + + - + ]: 4 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
167 : : {
5233 peter_e@gmx.net 168 : 1 : puts("pg_test_fsync (PostgreSQL) " PG_VERSION);
5346 bruce@momjian.us 169 : 1 : exit(0);
170 : : }
171 : : }
172 : :
4953 173 : 3 : while ((option = getopt_long(argc, argv, "f:s:",
5263 174 [ + - ]: 3 : long_options, &optindex)) != -1)
175 : : {
5346 176 [ - + + ]: 3 : switch (option)
177 : : {
5346 bruce@momjian.us 178 :UBC 0 : case 'f':
2317 michael@paquier.xyz 179 : 0 : filename = pg_strdup(optarg);
5346 bruce@momjian.us 180 : 0 : break;
181 : :
4953 bruce@momjian.us 182 :CBC 2 : case 's':
1804 michael@paquier.xyz 183 : 2 : errno = 0;
184 : 2 : optval = strtoul(optarg, &endptr, 10);
185 : :
186 [ + + + - ]: 2 : if (endptr == optarg || *endptr != '\0' ||
187 [ + - - + ]: 1 : errno != 0 || optval != (unsigned int) optval)
188 : : {
189 : 1 : pg_log_error("invalid argument for option %s", "--secs-per-test");
1247 tgl@sss.pgh.pa.us 190 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
1804 michael@paquier.xyz 191 : 1 : exit(1);
192 : : }
193 : :
194 : 1 : secs_per_test = (unsigned int) optval;
195 [ + - ]: 1 : if (secs_per_test == 0)
1247 tgl@sss.pgh.pa.us 196 : 1 : pg_fatal("%s must be in range %u..%u",
197 : : "--secs-per-test", 1, UINT_MAX);
5346 bruce@momjian.us 198 :UBC 0 : break;
199 : :
5346 bruce@momjian.us 200 :CBC 1 : default:
201 : : /* getopt_long already emitted a complaint */
1247 tgl@sss.pgh.pa.us 202 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
5346 bruce@momjian.us 203 : 1 : exit(1);
204 : : }
205 : : }
206 : :
5341 tgl@sss.pgh.pa.us 207 [ # # ]:UBC 0 : if (argc > optind)
208 : : {
2350 peter@eisentraut.org 209 : 0 : pg_log_error("too many command-line arguments (first is \"%s\")",
210 : : argv[optind]);
1247 tgl@sss.pgh.pa.us 211 : 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
5341 212 : 0 : exit(1);
213 : : }
214 : :
1804 michael@paquier.xyz 215 : 0 : printf(ngettext("%u second per test\n",
216 : : "%u seconds per test\n",
217 : : secs_per_test),
218 : : secs_per_test);
219 : : #if defined(O_DIRECT)
3249 peter_e@gmx.net 220 : 0 : printf(_("O_DIRECT supported on this platform for open_datasync and open_sync.\n"));
221 : : #elif defined(F_NOCACHE)
222 : : printf(_("F_NOCACHE supported on this platform for open_datasync and open_sync.\n"));
223 : : #else
224 : : printf(_("Direct I/O is not supported on this platform.\n"));
225 : : #endif
5348 bruce@momjian.us 226 : 0 : }
227 : :
228 : : static void
229 : 0 : prepare_buf(void)
230 : : {
231 : : int ops;
232 : :
233 : : /* write random data into buffer */
2909 andres@anarazel.de 234 [ # # ]: 0 : for (ops = 0; ops < DEFAULT_XLOG_SEG_SIZE; ops++)
1378 tgl@sss.pgh.pa.us 235 : 0 : full_buf[ops] = (char) pg_prng_int32(&pg_global_prng_state);
236 : :
4443 heikki.linnakangas@i 237 : 0 : buf = (char *) TYPEALIGN(XLOG_BLCKSZ, full_buf);
5348 bruce@momjian.us 238 : 0 : }
239 : :
240 : : static void
241 : 0 : test_open(void)
242 : : {
243 : : int tmpfile;
244 : :
245 : : /*
246 : : * test if we can open the target file
247 : : */
1878 michael@paquier.xyz 248 [ # # ]: 0 : if ((tmpfile = open(filename, O_RDWR | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR)) == -1)
5341 tgl@sss.pgh.pa.us 249 : 0 : die("could not open output file");
5020 rhaas@postgresql.org 250 : 0 : needs_unlink = 1;
2909 andres@anarazel.de 251 [ # # ]: 0 : if (write(tmpfile, full_buf, DEFAULT_XLOG_SEG_SIZE) !=
252 : : DEFAULT_XLOG_SEG_SIZE)
6860 bruce@momjian.us 253 : 0 : die("write failed");
254 : :
255 : : /* fsync now so that dirty buffers don't skew later tests */
256 [ # # ]: 0 : if (fsync(tmpfile) != 0)
257 : 0 : die("fsync failed");
258 : :
5348 259 : 0 : close(tmpfile);
260 : 0 : }
261 : :
262 : : static int
1510 tmunro@postgresql.or 263 : 0 : open_direct(const char *path, int flags, mode_t mode)
264 : : {
265 : : int fd;
266 : :
267 : : #ifdef O_DIRECT
268 : 0 : flags |= O_DIRECT;
269 : : #endif
270 : :
271 : 0 : fd = open(path, flags, mode);
272 : :
273 : : #if !defined(O_DIRECT) && defined(F_NOCACHE)
274 : : if (fd >= 0 && fcntl(fd, F_NOCACHE, 1) < 0)
275 : : {
276 : : int save_errno = errno;
277 : :
278 : : close(fd);
279 : : errno = save_errno;
280 : : return -1;
281 : : }
282 : : #endif
283 : :
284 : 0 : return fd;
285 : : }
286 : :
287 : : static void
5348 bruce@momjian.us 288 : 0 : test_sync(int writes_per_op)
289 : : {
290 : : int tmpfile,
291 : : ops,
292 : : writes;
293 : 0 : bool fs_warning = false;
294 : :
295 [ # # ]: 0 : if (writes_per_op == 1)
3249 peter_e@gmx.net 296 : 0 : printf(_("\nCompare file sync methods using one %dkB write:\n"), XLOG_BLCKSZ_K);
297 : : else
298 : 0 : printf(_("\nCompare file sync methods using two %dkB writes:\n"), XLOG_BLCKSZ_K);
477 peter@eisentraut.org 299 : 0 : printf(_("(in \"wal_sync_method\" preference order, except fdatasync is Linux's default)\n"));
300 : :
301 : : /*
302 : : * Test open_datasync if available
303 : : */
5294 bruce@momjian.us 304 : 0 : printf(LABEL_FORMAT, "open_datasync");
5534 305 : 0 : fflush(stdout);
306 : :
307 : : #ifdef O_DSYNC
1510 tmunro@postgresql.or 308 [ # # ]: 0 : if ((tmpfile = open_direct(filename, O_RDWR | O_DSYNC | PG_BINARY, 0)) == -1)
309 : : {
2934 peter_e@gmx.net 310 : 0 : printf(NA_FORMAT, _("n/a*"));
5348 bruce@momjian.us 311 : 0 : fs_warning = true;
312 : : }
313 : : else
314 : : {
4953 315 : 0 : START_TIMER;
316 [ # # ]: 0 : for (ops = 0; alarm_triggered == false; ops++)
317 : : {
5348 318 [ # # ]: 0 : for (writes = 0; writes < writes_per_op; writes++)
1073 tmunro@postgresql.or 319 [ # # ]: 0 : if (pg_pwrite(tmpfile,
320 : : buf,
321 : : XLOG_BLCKSZ,
322 : 0 : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
5348 bruce@momjian.us 323 : 0 : die("write failed");
324 : : }
4953 325 : 0 : STOP_TIMER;
5348 326 : 0 : close(tmpfile);
327 : : }
328 : : #else
329 : : printf(NA_FORMAT, _("n/a"));
330 : : #endif
331 : :
332 : : /*
333 : : * Test fdatasync if available
334 : : */
5345 335 : 0 : printf(LABEL_FORMAT, "fdatasync");
5534 336 : 0 : fflush(stdout);
337 : :
1878 michael@paquier.xyz 338 [ # # ]: 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
5341 tgl@sss.pgh.pa.us 339 : 0 : die("could not open output file");
4953 bruce@momjian.us 340 : 0 : START_TIMER;
341 [ # # ]: 0 : for (ops = 0; alarm_triggered == false; ops++)
342 : : {
5348 343 [ # # ]: 0 : for (writes = 0; writes < writes_per_op; writes++)
1073 tmunro@postgresql.or 344 [ # # ]: 0 : if (pg_pwrite(tmpfile,
345 : : buf,
346 : : XLOG_BLCKSZ,
347 : 0 : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
5348 bruce@momjian.us 348 : 0 : die("write failed");
5761 349 : 0 : fdatasync(tmpfile);
350 : : }
4953 351 : 0 : STOP_TIMER;
7842 352 : 0 : close(tmpfile);
353 : :
354 : : /*
355 : : * Test fsync
356 : : */
5345 357 : 0 : printf(LABEL_FORMAT, "fsync");
5534 358 : 0 : fflush(stdout);
359 : :
1878 michael@paquier.xyz 360 [ # # ]: 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
5341 tgl@sss.pgh.pa.us 361 : 0 : die("could not open output file");
4953 bruce@momjian.us 362 : 0 : START_TIMER;
363 [ # # ]: 0 : for (ops = 0; alarm_triggered == false; ops++)
364 : : {
5348 365 [ # # ]: 0 : for (writes = 0; writes < writes_per_op; writes++)
1073 tmunro@postgresql.or 366 [ # # ]: 0 : if (pg_pwrite(tmpfile,
367 : : buf,
368 : : XLOG_BLCKSZ,
369 : 0 : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
5348 bruce@momjian.us 370 : 0 : die("write failed");
5761 371 [ # # ]: 0 : if (fsync(tmpfile) != 0)
372 : 0 : die("fsync failed");
373 : : }
4953 374 : 0 : STOP_TIMER;
7842 375 : 0 : close(tmpfile);
376 : :
377 : : /*
378 : : * If fsync_writethrough is available, test as well
379 : : */
5345 380 : 0 : printf(LABEL_FORMAT, "fsync_writethrough");
5348 381 : 0 : fflush(stdout);
382 : :
383 : : #ifdef HAVE_FSYNC_WRITETHROUGH
384 : : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
385 : : die("could not open output file");
386 : : START_TIMER;
387 : : for (ops = 0; alarm_triggered == false; ops++)
388 : : {
389 : : for (writes = 0; writes < writes_per_op; writes++)
390 : : if (pg_pwrite(tmpfile,
391 : : buf,
392 : : XLOG_BLCKSZ,
393 : : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
394 : : die("write failed");
395 : : if (pg_fsync_writethrough(tmpfile) != 0)
396 : : die("fsync failed");
397 : : }
398 : : STOP_TIMER;
399 : : close(tmpfile);
400 : : #else
2934 peter_e@gmx.net 401 : 0 : printf(NA_FORMAT, _("n/a"));
402 : : #endif
403 : :
404 : : /*
405 : : * Test open_sync if available
406 : : */
5294 bruce@momjian.us 407 : 0 : printf(LABEL_FORMAT, "open_sync");
5534 408 : 0 : fflush(stdout);
409 : :
410 : : #ifdef O_SYNC
1142 tmunro@postgresql.or 411 [ # # ]: 0 : if ((tmpfile = open_direct(filename, O_RDWR | O_SYNC | PG_BINARY, 0)) == -1)
412 : : {
2934 peter_e@gmx.net 413 : 0 : printf(NA_FORMAT, _("n/a*"));
5348 bruce@momjian.us 414 : 0 : fs_warning = true;
415 : : }
416 : : else
417 : : {
4953 418 : 0 : START_TIMER;
419 [ # # ]: 0 : for (ops = 0; alarm_triggered == false; ops++)
420 : : {
5348 421 [ # # ]: 0 : for (writes = 0; writes < writes_per_op; writes++)
1073 tmunro@postgresql.or 422 [ # # ]: 0 : if (pg_pwrite(tmpfile,
423 : : buf,
424 : : XLOG_BLCKSZ,
425 : 0 : writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
426 : :
427 : : /*
428 : : * This can generate write failures if the filesystem has
429 : : * a large block size, e.g. 4k, and there is no support
430 : : * for O_DIRECT writes smaller than the file system block
431 : : * size, e.g. XFS.
432 : : */
5348 bruce@momjian.us 433 : 0 : die("write failed");
434 : : }
4953 435 : 0 : STOP_TIMER;
5348 436 : 0 : close(tmpfile);
437 : : }
438 : : #else
439 : : printf(NA_FORMAT, _("n/a"));
440 : : #endif
441 : :
442 [ # # ]: 0 : if (fs_warning)
443 : : {
3249 peter_e@gmx.net 444 : 0 : printf(_("* This file system and its mount options do not support direct\n"
445 : : " I/O, e.g. ext4 in journaled mode.\n"));
446 : : }
5348 bruce@momjian.us 447 : 0 : }
448 : :
449 : : static void
450 : 0 : test_open_syncs(void)
451 : : {
3249 peter_e@gmx.net 452 : 0 : printf(_("\nCompare open_sync with different write sizes:\n"));
453 : 0 : printf(_("(This is designed to compare the cost of writing 16kB in different write\n"
454 : : "open_sync sizes.)\n"));
455 : :
456 : 0 : test_open_sync(_(" 1 * 16kB open_sync write"), 16);
457 : 0 : test_open_sync(_(" 2 * 8kB open_sync writes"), 8);
458 : 0 : test_open_sync(_(" 4 * 4kB open_sync writes"), 4);
459 : 0 : test_open_sync(_(" 8 * 2kB open_sync writes"), 2);
460 : 0 : test_open_sync(_("16 * 1kB open_sync writes"), 1);
5345 bruce@momjian.us 461 : 0 : }
462 : :
463 : : /*
464 : : * Test open_sync with different size files
465 : : */
466 : : static void
467 : 0 : test_open_sync(const char *msg, int writes_size)
468 : : {
469 : : #ifdef O_SYNC
470 : : int tmpfile,
471 : : ops,
472 : : writes;
473 : : #endif
474 : :
5294 475 : 0 : printf(LABEL_FORMAT, msg);
476 : 0 : fflush(stdout);
477 : :
478 : : #ifdef O_SYNC
1142 tmunro@postgresql.or 479 [ # # ]: 0 : if ((tmpfile = open_direct(filename, O_RDWR | O_SYNC | PG_BINARY, 0)) == -1)
2934 peter_e@gmx.net 480 : 0 : printf(NA_FORMAT, _("n/a*"));
481 : : else
482 : : {
4953 bruce@momjian.us 483 : 0 : START_TIMER;
484 [ # # ]: 0 : for (ops = 0; alarm_triggered == false; ops++)
485 : : {
5345 486 [ # # ]: 0 : for (writes = 0; writes < 16 / writes_size; writes++)
1073 tmunro@postgresql.or 487 : 0 : if (pg_pwrite(tmpfile,
488 : : buf,
489 : 0 : writes_size * 1024,
490 : 0 : writes * writes_size * 1024) !=
5339 bruce@momjian.us 491 [ # # ]: 0 : writes_size * 1024)
5345 492 : 0 : die("write failed");
493 : : }
4953 494 : 0 : STOP_TIMER;
5348 495 : 0 : close(tmpfile);
496 : : }
497 : : #else
498 : : printf(NA_FORMAT, _("n/a"));
499 : : #endif
500 : 0 : }
501 : :
502 : : static void
503 : 0 : test_file_descriptor_sync(void)
504 : : {
505 : : int tmpfile,
506 : : ops;
507 : :
508 : : /*
509 : : * Test whether fsync can sync data written on a different descriptor for
510 : : * the same file. This checks the efficiency of multi-process fsyncs
511 : : * against the same file. Possibly this should be done with writethrough
512 : : * on platforms which support it.
513 : : */
3249 peter_e@gmx.net 514 : 0 : printf(_("\nTest if fsync on non-write file descriptor is honored:\n"));
515 : 0 : printf(_("(If the times are similar, fsync() can sync data written on a different\n"
516 : : "descriptor.)\n"));
517 : :
518 : : /*
519 : : * first write, fsync and close, which is the normal behavior without
520 : : * multiple descriptors
521 : : */
5345 bruce@momjian.us 522 : 0 : printf(LABEL_FORMAT, "write, fsync, close");
5534 523 : 0 : fflush(stdout);
524 : :
4953 525 : 0 : START_TIMER;
526 [ # # ]: 0 : for (ops = 0; alarm_triggered == false; ops++)
527 : : {
1878 michael@paquier.xyz 528 [ # # ]: 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
5341 tgl@sss.pgh.pa.us 529 : 0 : die("could not open output file");
5339 bruce@momjian.us 530 [ # # ]: 0 : if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
6860 531 : 0 : die("write failed");
5761 532 [ # # ]: 0 : if (fsync(tmpfile) != 0)
533 : 0 : die("fsync failed");
534 : 0 : close(tmpfile);
535 : :
536 : : /*
537 : : * open and close the file again to be consistent with the following
538 : : * test
539 : : */
1878 michael@paquier.xyz 540 [ # # ]: 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
5341 tgl@sss.pgh.pa.us 541 : 0 : die("could not open output file");
5761 bruce@momjian.us 542 : 0 : close(tmpfile);
543 : : }
4953 544 : 0 : STOP_TIMER;
545 : :
546 : : /*
547 : : * Now open, write, close, open again and fsync This simulates processes
548 : : * fsyncing each other's writes.
549 : : */
5342 tgl@sss.pgh.pa.us 550 : 0 : printf(LABEL_FORMAT, "write, close, fsync");
551 : 0 : fflush(stdout);
552 : :
4953 bruce@momjian.us 553 : 0 : START_TIMER;
554 [ # # ]: 0 : for (ops = 0; alarm_triggered == false; ops++)
555 : : {
1878 michael@paquier.xyz 556 [ # # ]: 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
5341 tgl@sss.pgh.pa.us 557 : 0 : die("could not open output file");
5339 bruce@momjian.us 558 [ # # ]: 0 : if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
6860 559 : 0 : die("write failed");
5761 560 : 0 : close(tmpfile);
561 : : /* reopen file */
1878 michael@paquier.xyz 562 [ # # ]: 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
5341 tgl@sss.pgh.pa.us 563 : 0 : die("could not open output file");
6860 bruce@momjian.us 564 [ # # ]: 0 : if (fsync(tmpfile) != 0)
565 : 0 : die("fsync failed");
5761 566 : 0 : close(tmpfile);
567 : : }
4953 568 : 0 : STOP_TIMER;
7842 569 : 0 : }
570 : :
571 : : static void
5345 572 : 0 : test_non_sync(void)
573 : : {
574 : : int tmpfile,
575 : : ops;
576 : :
577 : : /*
578 : : * Test a simple write without fsync
579 : : */
3249 peter_e@gmx.net 580 : 0 : printf(_("\nNon-sync'ed %dkB writes:\n"), XLOG_BLCKSZ_K);
5345 bruce@momjian.us 581 : 0 : printf(LABEL_FORMAT, "write");
582 : 0 : fflush(stdout);
583 : :
1664 tmunro@postgresql.or 584 [ # # ]: 0 : if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
585 : 0 : die("could not open output file");
4953 bruce@momjian.us 586 : 0 : START_TIMER;
587 [ # # ]: 0 : for (ops = 0; alarm_triggered == false; ops++)
588 : : {
1073 tmunro@postgresql.or 589 [ # # ]: 0 : if (pg_pwrite(tmpfile, buf, XLOG_BLCKSZ, 0) != XLOG_BLCKSZ)
5345 bruce@momjian.us 590 : 0 : die("write failed");
591 : : }
4953 592 : 0 : STOP_TIMER;
1664 tmunro@postgresql.or 593 : 0 : close(tmpfile);
5345 bruce@momjian.us 594 : 0 : }
595 : :
596 : : static void
1088 tgl@sss.pgh.pa.us 597 : 0 : signal_cleanup(SIGNAL_ARGS)
598 : : {
599 : : int rc;
600 : :
601 : : /* Delete the file if it exists. Ignore errors */
5020 rhaas@postgresql.org 602 [ # # ]: 0 : if (needs_unlink)
603 : 0 : unlink(filename);
604 : : /* Finish incomplete line on stdout */
640 nathan@postgresql.or 605 : 0 : rc = write(STDOUT_FILENO, "\n", 1);
606 : : (void) rc; /* silence compiler warnings */
peter@eisentraut.org 607 : 0 : _exit(1);
608 : : }
609 : :
610 : : #ifdef HAVE_FSYNC_WRITETHROUGH
611 : :
612 : : static int
613 : : pg_fsync_writethrough(int fd)
614 : : {
615 : : #if defined(F_FULLFSYNC)
616 : : return (fcntl(fd, F_FULLFSYNC, 0) == -1) ? -1 : 0;
617 : : #else
618 : : errno = ENOSYS;
619 : : return -1;
620 : : #endif
621 : : }
622 : : #endif
623 : :
624 : : /*
625 : : * print out the writes per second for tests
626 : : */
627 : : static void
4953 bruce@momjian.us 628 : 0 : print_elapse(struct timeval start_t, struct timeval stop_t, int ops)
629 : : {
5541 630 : 0 : double total_time = (stop_t.tv_sec - start_t.tv_sec) +
841 tgl@sss.pgh.pa.us 631 : 0 : (stop_t.tv_usec - start_t.tv_usec) * 0.000001;
4953 bruce@momjian.us 632 : 0 : double per_second = ops / total_time;
4715 simon@2ndQuadrant.co 633 : 0 : double avg_op_time_us = (total_time / ops) * USECS_SEC;
634 : :
2934 peter_e@gmx.net 635 : 0 : printf(_(OPS_FORMAT), per_second, avg_op_time_us);
7842 bruce@momjian.us 636 : 0 : }
637 : :
638 : : #ifndef WIN32
639 : : static void
1088 tgl@sss.pgh.pa.us 640 : 0 : process_alarm(SIGNAL_ARGS)
641 : : {
4953 bruce@momjian.us 642 : 0 : alarm_triggered = true;
4952 643 : 0 : }
644 : : #else
645 : : static DWORD WINAPI
646 : : process_alarm(LPVOID param)
647 : : {
648 : : /* WIN32 doesn't support alarm, so we create a thread and sleep here */
649 : : Sleep(secs_per_test * 1000);
650 : : alarm_triggered = true;
651 : : ExitThread(0);
652 : : }
653 : : #endif
|