LCOV - code coverage report
Current view: top level - src/bin/pg_test_fsync - pg_test_fsync.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 13.7 % 226 31
Test Date: 2026-10-16 23:15:56 Functions: 15.4 % 13 2
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 14.7 % 109 16

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * pg_test_fsync --- tests all supported fsync() methods
       4                 :             :  *
       5                 :             :  * Portions Copyright (c) 1996-2026, 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                 :             :     HANDLE      alarm_thread; \
      53                 :             : \
      54                 :             :     alarm_triggered = false; \
      55                 :             :     alarm_thread = CreateThread(NULL, 0, process_alarm, NULL, 0, NULL); \
      56                 :             :     if (alarm_thread == NULL) \
      57                 :             :         pg_fatal("could not create thread for alarm"); \
      58                 :             :     CloseHandle(alarm_thread); \
      59                 :             :     gettimeofday(&start_t, NULL); \
      60                 :             : } while (0)
      61                 :             : #endif
      62                 :             : 
      63                 :             : #define STOP_TIMER  \
      64                 :             : do { \
      65                 :             :     gettimeofday(&stop_t, NULL); \
      66                 :             :     print_elapse(start_t, stop_t, ops); \
      67                 :             : } while (0)
      68                 :             : 
      69                 :             : 
      70                 :             : static const char *progname;
      71                 :             : 
      72                 :             : static unsigned int secs_per_test = 5;
      73                 :             : static int  needs_unlink = 0;
      74                 :             : alignas(PGAlignedXLogBlock) static char buf[DEFAULT_XLOG_SEG_SIZE];
      75                 :             : static char *filename = FSYNC_FILENAME;
      76                 :             : static struct timeval start_t,
      77                 :             :             stop_t;
      78                 :             : static sig_atomic_t alarm_triggered = false;
      79                 :             : 
      80                 :             : 
      81                 :             : static void handle_args(int argc, char *argv[]);
      82                 :             : static void prepare_buf(void);
      83                 :             : static void test_open(void);
      84                 :             : static void test_non_sync(void);
      85                 :             : static void test_sync(int writes_per_op);
      86                 :             : static void test_open_syncs(void);
      87                 :             : static void test_open_sync(const char *msg, int writes_size);
      88                 :             : static void test_file_descriptor_sync(void);
      89                 :             : 
      90                 :             : #ifndef WIN32
      91                 :             : static void process_alarm(SIGNAL_ARGS);
      92                 :             : #else
      93                 :             : static DWORD WINAPI process_alarm(LPVOID param);
      94                 :             : #endif
      95                 :             : static void signal_cleanup(SIGNAL_ARGS);
      96                 :             : 
      97                 :             : #ifdef HAVE_FSYNC_WRITETHROUGH
      98                 :             : static int  pg_fsync_writethrough(int fd);
      99                 :             : #endif
     100                 :             : static void print_elapse(struct timeval start_t, struct timeval stop_t, int ops);
     101                 :             : 
     102                 :             : #define die(msg) pg_fatal("%s: %m", _(msg))
     103                 :             : 
     104                 :             : 
     105                 :             : int
     106                 :           5 : main(int argc, char *argv[])
     107                 :             : {
     108                 :           5 :     pg_logging_init(argv[0]);
     109                 :           5 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_fsync"));
     110                 :           5 :     progname = get_progname(argv[0]);
     111                 :             : 
     112                 :           5 :     handle_args(argc, argv);
     113                 :             : 
     114                 :             :     /* Prevent leaving behind the test file */
     115                 :           0 :     pqsignal(SIGINT, signal_cleanup);
     116                 :           0 :     pqsignal(SIGTERM, signal_cleanup);
     117                 :             : 
     118                 :             :     /* the following are not valid on Windows */
     119                 :             : #ifndef WIN32
     120                 :           0 :     pqsignal(SIGALRM, process_alarm);
     121                 :           0 :     pqsignal(SIGHUP, signal_cleanup);
     122                 :             : #endif
     123                 :             : 
     124                 :           0 :     pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
     125                 :             : 
     126                 :           0 :     prepare_buf();
     127                 :             : 
     128                 :           0 :     test_open();
     129                 :             : 
     130                 :             :     /* Test using 1 XLOG_BLCKSZ write */
     131                 :           0 :     test_sync(1);
     132                 :             : 
     133                 :             :     /* Test using 2 XLOG_BLCKSZ writes */
     134                 :           0 :     test_sync(2);
     135                 :             : 
     136                 :           0 :     test_open_syncs();
     137                 :             : 
     138                 :           0 :     test_file_descriptor_sync();
     139                 :             : 
     140                 :           0 :     test_non_sync();
     141                 :             : 
     142                 :           0 :     unlink(filename);
     143                 :             : 
     144                 :           0 :     return 0;
     145                 :             : }
     146                 :             : 
     147                 :             : static void
     148                 :           5 : handle_args(int argc, char *argv[])
     149                 :             : {
     150                 :             :     static struct option long_options[] = {
     151                 :             :         {"filename", required_argument, NULL, 'f'},
     152                 :             :         {"secs-per-test", required_argument, NULL, 's'},
     153                 :             :         {NULL, 0, NULL, 0}
     154                 :             :     };
     155                 :             : 
     156                 :             :     int         option;         /* Command line option */
     157                 :           5 :     int         optindex = 0;   /* used by getopt_long */
     158                 :             :     unsigned long optval;       /* used for option parsing */
     159                 :             :     char       *endptr;
     160                 :             : 
     161         [ +  - ]:           5 :     if (argc > 1)
     162                 :             :     {
     163   [ +  +  -  + ]:           5 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     164                 :             :         {
     165                 :           1 :             printf(_("Usage: %s [-f FILENAME] [-s SECS-PER-TEST]\n"), progname);
     166                 :           1 :             exit(0);
     167                 :             :         }
     168   [ +  +  -  + ]:           4 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     169                 :             :         {
     170                 :           1 :             puts("pg_test_fsync (PostgreSQL) " PG_VERSION);
     171                 :           1 :             exit(0);
     172                 :             :         }
     173                 :             :     }
     174                 :             : 
     175                 :           3 :     while ((option = getopt_long(argc, argv, "f:s:",
     176         [ +  - ]:           3 :                                  long_options, &optindex)) != -1)
     177                 :             :     {
     178      [ -  +  + ]:           3 :         switch (option)
     179                 :             :         {
     180                 :           0 :             case 'f':
     181                 :           0 :                 filename = pg_strdup(optarg);
     182                 :           0 :                 break;
     183                 :             : 
     184                 :           2 :             case 's':
     185                 :           2 :                 errno = 0;
     186                 :           2 :                 optval = strtoul(optarg, &endptr, 10);
     187                 :             : 
     188   [ +  +  +  - ]:           2 :                 if (endptr == optarg || *endptr != '\0' ||
     189   [ +  -  -  + ]:           1 :                     errno != 0 || optval != (unsigned int) optval)
     190                 :             :                 {
     191                 :           1 :                     pg_log_error("invalid argument for option %s", "--secs-per-test");
     192                 :           1 :                     pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     193                 :           1 :                     exit(1);
     194                 :             :                 }
     195                 :             : 
     196                 :           1 :                 secs_per_test = (unsigned int) optval;
     197         [ +  - ]:           1 :                 if (secs_per_test == 0)
     198                 :           1 :                     pg_fatal("%s must be in range %u..%u",
     199                 :             :                              "--secs-per-test", 1, UINT_MAX);
     200                 :           0 :                 break;
     201                 :             : 
     202                 :           1 :             default:
     203                 :             :                 /* getopt_long already emitted a complaint */
     204                 :           1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     205                 :           1 :                 exit(1);
     206                 :             :         }
     207                 :             :     }
     208                 :             : 
     209         [ #  # ]:           0 :     if (argc > optind)
     210                 :             :     {
     211                 :           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     212                 :             :                      argv[optind]);
     213                 :           0 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     214                 :           0 :         exit(1);
     215                 :             :     }
     216                 :             : 
     217                 :           0 :     printf(ngettext("%u second per test\n",
     218                 :             :                     "%u seconds per test\n",
     219                 :             :                     secs_per_test),
     220                 :             :            secs_per_test);
     221                 :             : #if defined(O_DIRECT)
     222                 :           0 :     printf(_("O_DIRECT supported on this platform for open_datasync and open_sync.\n"));
     223                 :             : #elif defined(F_NOCACHE)
     224                 :             :     printf(_("F_NOCACHE supported on this platform for open_datasync and open_sync.\n"));
     225                 :             : #else
     226                 :             :     printf(_("Direct I/O is not supported on this platform.\n"));
     227                 :             : #endif
     228                 :           0 : }
     229                 :             : 
     230                 :             : static void
     231                 :           0 : prepare_buf(void)
     232                 :             : {
     233                 :             :     int         ops;
     234                 :             : 
     235                 :             :     /* write random data into buffer */
     236         [ #  # ]:           0 :     for (ops = 0; ops < DEFAULT_XLOG_SEG_SIZE; ops++)
     237                 :           0 :         buf[ops] = (char) pg_prng_int32(&pg_global_prng_state);
     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                 :             :      */
     248         [ #  # ]:           0 :     if ((tmpfile = open(filename, O_RDWR | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR)) == -1)
     249                 :           0 :         die("could not open output file");
     250                 :           0 :     needs_unlink = 1;
     251         [ #  # ]:           0 :     if (write(tmpfile, buf, DEFAULT_XLOG_SEG_SIZE) !=
     252                 :             :         DEFAULT_XLOG_SEG_SIZE)
     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                 :             : 
     259                 :           0 :     close(tmpfile);
     260                 :           0 : }
     261                 :             : 
     262                 :             : static int
     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
     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)
     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);
     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                 :             :      */
     304                 :           0 :     printf(LABEL_FORMAT, "open_datasync");
     305                 :           0 :     fflush(stdout);
     306                 :             : 
     307                 :             : #ifdef O_DSYNC
     308         [ #  # ]:           0 :     if ((tmpfile = open_direct(filename, O_RDWR | O_DSYNC | PG_BINARY, 0)) == -1)
     309                 :             :     {
     310                 :           0 :         printf(NA_FORMAT, _("n/a*"));
     311                 :           0 :         fs_warning = true;
     312                 :             :     }
     313                 :             :     else
     314                 :             :     {
     315                 :           0 :         START_TIMER;
     316         [ #  # ]:           0 :         for (ops = 0; alarm_triggered == false; ops++)
     317                 :             :         {
     318         [ #  # ]:           0 :             for (writes = 0; writes < writes_per_op; writes++)
     319         [ #  # ]:           0 :                 if (pg_pwrite(tmpfile,
     320                 :             :                               buf,
     321                 :             :                               XLOG_BLCKSZ,
     322                 :           0 :                               writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
     323                 :           0 :                     die("write failed");
     324                 :             :         }
     325                 :           0 :         STOP_TIMER;
     326                 :           0 :         close(tmpfile);
     327                 :             :     }
     328                 :             : #else
     329                 :             :     printf(NA_FORMAT, _("n/a"));
     330                 :             : #endif
     331                 :             : 
     332                 :             : /*
     333                 :             :  * Test fdatasync if available
     334                 :             :  */
     335                 :           0 :     printf(LABEL_FORMAT, "fdatasync");
     336                 :           0 :     fflush(stdout);
     337                 :             : 
     338         [ #  # ]:           0 :     if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     339                 :           0 :         die("could not open output file");
     340                 :           0 :     START_TIMER;
     341         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     342                 :             :     {
     343         [ #  # ]:           0 :         for (writes = 0; writes < writes_per_op; writes++)
     344         [ #  # ]:           0 :             if (pg_pwrite(tmpfile,
     345                 :             :                           buf,
     346                 :             :                           XLOG_BLCKSZ,
     347                 :           0 :                           writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
     348                 :           0 :                 die("write failed");
     349                 :           0 :         fdatasync(tmpfile);
     350                 :             :     }
     351                 :           0 :     STOP_TIMER;
     352                 :           0 :     close(tmpfile);
     353                 :             : 
     354                 :             : /*
     355                 :             :  * Test fsync
     356                 :             :  */
     357                 :           0 :     printf(LABEL_FORMAT, "fsync");
     358                 :           0 :     fflush(stdout);
     359                 :             : 
     360         [ #  # ]:           0 :     if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     361                 :           0 :         die("could not open output file");
     362                 :           0 :     START_TIMER;
     363         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     364                 :             :     {
     365         [ #  # ]:           0 :         for (writes = 0; writes < writes_per_op; writes++)
     366         [ #  # ]:           0 :             if (pg_pwrite(tmpfile,
     367                 :             :                           buf,
     368                 :             :                           XLOG_BLCKSZ,
     369                 :           0 :                           writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
     370                 :           0 :                 die("write failed");
     371         [ #  # ]:           0 :         if (fsync(tmpfile) != 0)
     372                 :           0 :             die("fsync failed");
     373                 :             :     }
     374                 :           0 :     STOP_TIMER;
     375                 :           0 :     close(tmpfile);
     376                 :             : 
     377                 :             : /*
     378                 :             :  * If fsync_writethrough is available, test as well
     379                 :             :  */
     380                 :           0 :     printf(LABEL_FORMAT, "fsync_writethrough");
     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
     401                 :           0 :     printf(NA_FORMAT, _("n/a"));
     402                 :             : #endif
     403                 :             : 
     404                 :             : /*
     405                 :             :  * Test open_sync if available
     406                 :             :  */
     407                 :           0 :     printf(LABEL_FORMAT, "open_sync");
     408                 :           0 :     fflush(stdout);
     409                 :             : 
     410                 :             : #ifdef O_SYNC
     411         [ #  # ]:           0 :     if ((tmpfile = open_direct(filename, O_RDWR | O_SYNC | PG_BINARY, 0)) == -1)
     412                 :             :     {
     413                 :           0 :         printf(NA_FORMAT, _("n/a*"));
     414                 :           0 :         fs_warning = true;
     415                 :             :     }
     416                 :             :     else
     417                 :             :     {
     418                 :           0 :         START_TIMER;
     419         [ #  # ]:           0 :         for (ops = 0; alarm_triggered == false; ops++)
     420                 :             :         {
     421         [ #  # ]:           0 :             for (writes = 0; writes < writes_per_op; writes++)
     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                 :             :                      */
     433                 :           0 :                     die("write failed");
     434                 :             :         }
     435                 :           0 :         STOP_TIMER;
     436                 :           0 :         close(tmpfile);
     437                 :             :     }
     438                 :             : #else
     439                 :             :     printf(NA_FORMAT, _("n/a"));
     440                 :             : #endif
     441                 :             : 
     442         [ #  # ]:           0 :     if (fs_warning)
     443                 :             :     {
     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                 :             :     }
     447                 :           0 : }
     448                 :             : 
     449                 :             : static void
     450                 :           0 : test_open_syncs(void)
     451                 :             : {
     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);
     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                 :             : 
     475                 :           0 :     printf(LABEL_FORMAT, msg);
     476                 :           0 :     fflush(stdout);
     477                 :             : 
     478                 :             : #ifdef O_SYNC
     479         [ #  # ]:           0 :     if ((tmpfile = open_direct(filename, O_RDWR | O_SYNC | PG_BINARY, 0)) == -1)
     480                 :           0 :         printf(NA_FORMAT, _("n/a*"));
     481                 :             :     else
     482                 :             :     {
     483                 :           0 :         START_TIMER;
     484         [ #  # ]:           0 :         for (ops = 0; alarm_triggered == false; ops++)
     485                 :             :         {
     486         [ #  # ]:           0 :             for (writes = 0; writes < 16 / writes_size; writes++)
     487                 :           0 :                 if (pg_pwrite(tmpfile,
     488                 :             :                               buf,
     489                 :           0 :                               writes_size * 1024,
     490                 :           0 :                               writes * writes_size * 1024) !=
     491         [ #  # ]:           0 :                     writes_size * 1024)
     492                 :           0 :                     die("write failed");
     493                 :             :         }
     494                 :           0 :         STOP_TIMER;
     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                 :             :      */
     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                 :             :      */
     522                 :           0 :     printf(LABEL_FORMAT, "write, fsync, close");
     523                 :           0 :     fflush(stdout);
     524                 :             : 
     525                 :           0 :     START_TIMER;
     526         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     527                 :             :     {
     528         [ #  # ]:           0 :         if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     529                 :           0 :             die("could not open output file");
     530         [ #  # ]:           0 :         if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
     531                 :           0 :             die("write failed");
     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                 :             :          */
     540         [ #  # ]:           0 :         if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     541                 :           0 :             die("could not open output file");
     542                 :           0 :         close(tmpfile);
     543                 :             :     }
     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                 :             :      */
     550                 :           0 :     printf(LABEL_FORMAT, "write, close, fsync");
     551                 :           0 :     fflush(stdout);
     552                 :             : 
     553                 :           0 :     START_TIMER;
     554         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     555                 :             :     {
     556         [ #  # ]:           0 :         if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     557                 :           0 :             die("could not open output file");
     558         [ #  # ]:           0 :         if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
     559                 :           0 :             die("write failed");
     560                 :           0 :         close(tmpfile);
     561                 :             :         /* reopen file */
     562         [ #  # ]:           0 :         if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     563                 :           0 :             die("could not open output file");
     564         [ #  # ]:           0 :         if (fsync(tmpfile) != 0)
     565                 :           0 :             die("fsync failed");
     566                 :           0 :         close(tmpfile);
     567                 :             :     }
     568                 :           0 :     STOP_TIMER;
     569                 :           0 : }
     570                 :             : 
     571                 :             : static void
     572                 :           0 : test_non_sync(void)
     573                 :             : {
     574                 :             :     int         tmpfile,
     575                 :             :                 ops;
     576                 :             : 
     577                 :             :     /*
     578                 :             :      * Test a simple write without fsync
     579                 :             :      */
     580                 :           0 :     printf(_("\nNon-sync'ed %dkB writes:\n"), XLOG_BLCKSZ_K);
     581                 :           0 :     printf(LABEL_FORMAT, "write");
     582                 :           0 :     fflush(stdout);
     583                 :             : 
     584         [ #  # ]:           0 :     if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     585                 :           0 :         die("could not open output file");
     586                 :           0 :     START_TIMER;
     587         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     588                 :             :     {
     589         [ #  # ]:           0 :         if (pg_pwrite(tmpfile, buf, XLOG_BLCKSZ, 0) != XLOG_BLCKSZ)
     590                 :           0 :             die("write failed");
     591                 :             :     }
     592                 :           0 :     STOP_TIMER;
     593                 :           0 :     close(tmpfile);
     594                 :           0 : }
     595                 :             : 
     596                 :             : static void
     597                 :           0 : signal_cleanup(SIGNAL_ARGS)
     598                 :             : {
     599                 :             :     ssize_t     rc;
     600                 :             : 
     601                 :             :     /* Delete the file if it exists. Ignore errors */
     602         [ #  # ]:           0 :     if (needs_unlink)
     603                 :           0 :         unlink(filename);
     604                 :             :     /* Finish incomplete line on stdout */
     605                 :           0 :     rc = write(STDOUT_FILENO, "\n", 1);
     606                 :             :     (void) rc;                  /* silence compiler warnings */
     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
     628                 :           0 : print_elapse(struct timeval start_t, struct timeval stop_t, int ops)
     629                 :             : {
     630                 :           0 :     double      total_time = (stop_t.tv_sec - start_t.tv_sec) +
     631                 :           0 :         (stop_t.tv_usec - start_t.tv_usec) * 0.000001;
     632                 :           0 :     double      per_second = ops / total_time;
     633                 :           0 :     double      avg_op_time_us = (total_time / ops) * USECS_SEC;
     634                 :             : 
     635                 :           0 :     printf(_(OPS_FORMAT), per_second, avg_op_time_us);
     636                 :           0 : }
     637                 :             : 
     638                 :             : #ifndef WIN32
     639                 :             : static void
     640                 :           0 : process_alarm(SIGNAL_ARGS)
     641                 :             : {
     642                 :           0 :     alarm_triggered = true;
     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
        

Generated by: LCOV version 2.0-1