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