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-07-25 22:15:46 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                 :             :     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
     103                 :           5 : main(int argc, char *argv[])
     104                 :             : {
     105                 :           5 :     pg_logging_init(argv[0]);
     106                 :           5 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_fsync"));
     107                 :           5 :     progname = get_progname(argv[0]);
     108                 :             : 
     109                 :           5 :     handle_args(argc, argv);
     110                 :             : 
     111                 :             :     /* Prevent leaving behind the test file */
     112                 :           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                 :             : 
     121                 :           0 :     pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
     122                 :             : 
     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                 :             : 
     137                 :           0 :     test_non_sync();
     138                 :             : 
     139                 :           0 :     unlink(filename);
     140                 :             : 
     141                 :           0 :     return 0;
     142                 :             : }
     143                 :             : 
     144                 :             : static void
     145                 :           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 */
     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                 :             :     {
     160   [ +  +  -  + ]:           5 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     161                 :             :         {
     162                 :           1 :             printf(_("Usage: %s [-f FILENAME] [-s SECS-PER-TEST]\n"), progname);
     163                 :           1 :             exit(0);
     164                 :             :         }
     165   [ +  +  -  + ]:           4 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     166                 :             :         {
     167                 :           1 :             puts("pg_test_fsync (PostgreSQL) " PG_VERSION);
     168                 :           1 :             exit(0);
     169                 :             :         }
     170                 :             :     }
     171                 :             : 
     172                 :           3 :     while ((option = getopt_long(argc, argv, "f:s:",
     173         [ +  - ]:           3 :                                  long_options, &optindex)) != -1)
     174                 :             :     {
     175      [ -  +  + ]:           3 :         switch (option)
     176                 :             :         {
     177                 :           0 :             case 'f':
     178                 :           0 :                 filename = pg_strdup(optarg);
     179                 :           0 :                 break;
     180                 :             : 
     181                 :           2 :             case 's':
     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");
     189                 :           1 :                     pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     190                 :           1 :                     exit(1);
     191                 :             :                 }
     192                 :             : 
     193                 :           1 :                 secs_per_test = (unsigned int) optval;
     194         [ +  - ]:           1 :                 if (secs_per_test == 0)
     195                 :           1 :                     pg_fatal("%s must be in range %u..%u",
     196                 :             :                              "--secs-per-test", 1, UINT_MAX);
     197                 :           0 :                 break;
     198                 :             : 
     199                 :           1 :             default:
     200                 :             :                 /* getopt_long already emitted a complaint */
     201                 :           1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     202                 :           1 :                 exit(1);
     203                 :             :         }
     204                 :             :     }
     205                 :             : 
     206         [ #  # ]:           0 :     if (argc > optind)
     207                 :             :     {
     208                 :           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     209                 :             :                      argv[optind]);
     210                 :           0 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     211                 :           0 :         exit(1);
     212                 :             :     }
     213                 :             : 
     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)
     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
     225                 :           0 : }
     226                 :             : 
     227                 :             : static void
     228                 :           0 : prepare_buf(void)
     229                 :             : {
     230                 :             :     int         ops;
     231                 :             : 
     232                 :             :     /* write random data into buffer */
     233         [ #  # ]:           0 :     for (ops = 0; ops < DEFAULT_XLOG_SEG_SIZE; ops++)
     234                 :           0 :         buf[ops] = (char) pg_prng_int32(&pg_global_prng_state);
     235                 :           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                 :             :      */
     245         [ #  # ]:           0 :     if ((tmpfile = open(filename, O_RDWR | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR)) == -1)
     246                 :           0 :         die("could not open output file");
     247                 :           0 :     needs_unlink = 1;
     248         [ #  # ]:           0 :     if (write(tmpfile, buf, DEFAULT_XLOG_SEG_SIZE) !=
     249                 :             :         DEFAULT_XLOG_SEG_SIZE)
     250                 :           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                 :             : 
     256                 :           0 :     close(tmpfile);
     257                 :           0 : }
     258                 :             : 
     259                 :             : static int
     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
     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)
     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);
     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                 :             :      */
     301                 :           0 :     printf(LABEL_FORMAT, "open_datasync");
     302                 :           0 :     fflush(stdout);
     303                 :             : 
     304                 :             : #ifdef O_DSYNC
     305         [ #  # ]:           0 :     if ((tmpfile = open_direct(filename, O_RDWR | O_DSYNC | PG_BINARY, 0)) == -1)
     306                 :             :     {
     307                 :           0 :         printf(NA_FORMAT, _("n/a*"));
     308                 :           0 :         fs_warning = true;
     309                 :             :     }
     310                 :             :     else
     311                 :             :     {
     312                 :           0 :         START_TIMER;
     313         [ #  # ]:           0 :         for (ops = 0; alarm_triggered == false; ops++)
     314                 :             :         {
     315         [ #  # ]:           0 :             for (writes = 0; writes < writes_per_op; writes++)
     316         [ #  # ]:           0 :                 if (pg_pwrite(tmpfile,
     317                 :             :                               buf,
     318                 :             :                               XLOG_BLCKSZ,
     319                 :           0 :                               writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
     320                 :           0 :                     die("write failed");
     321                 :             :         }
     322                 :           0 :         STOP_TIMER;
     323                 :           0 :         close(tmpfile);
     324                 :             :     }
     325                 :             : #else
     326                 :             :     printf(NA_FORMAT, _("n/a"));
     327                 :             : #endif
     328                 :             : 
     329                 :             : /*
     330                 :             :  * Test fdatasync if available
     331                 :             :  */
     332                 :           0 :     printf(LABEL_FORMAT, "fdatasync");
     333                 :           0 :     fflush(stdout);
     334                 :             : 
     335         [ #  # ]:           0 :     if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     336                 :           0 :         die("could not open output file");
     337                 :           0 :     START_TIMER;
     338         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     339                 :             :     {
     340         [ #  # ]:           0 :         for (writes = 0; writes < writes_per_op; writes++)
     341         [ #  # ]:           0 :             if (pg_pwrite(tmpfile,
     342                 :             :                           buf,
     343                 :             :                           XLOG_BLCKSZ,
     344                 :           0 :                           writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
     345                 :           0 :                 die("write failed");
     346                 :           0 :         fdatasync(tmpfile);
     347                 :             :     }
     348                 :           0 :     STOP_TIMER;
     349                 :           0 :     close(tmpfile);
     350                 :             : 
     351                 :             : /*
     352                 :             :  * Test fsync
     353                 :             :  */
     354                 :           0 :     printf(LABEL_FORMAT, "fsync");
     355                 :           0 :     fflush(stdout);
     356                 :             : 
     357         [ #  # ]:           0 :     if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     358                 :           0 :         die("could not open output file");
     359                 :           0 :     START_TIMER;
     360         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     361                 :             :     {
     362         [ #  # ]:           0 :         for (writes = 0; writes < writes_per_op; writes++)
     363         [ #  # ]:           0 :             if (pg_pwrite(tmpfile,
     364                 :             :                           buf,
     365                 :             :                           XLOG_BLCKSZ,
     366                 :           0 :                           writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
     367                 :           0 :                 die("write failed");
     368         [ #  # ]:           0 :         if (fsync(tmpfile) != 0)
     369                 :           0 :             die("fsync failed");
     370                 :             :     }
     371                 :           0 :     STOP_TIMER;
     372                 :           0 :     close(tmpfile);
     373                 :             : 
     374                 :             : /*
     375                 :             :  * If fsync_writethrough is available, test as well
     376                 :             :  */
     377                 :           0 :     printf(LABEL_FORMAT, "fsync_writethrough");
     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
     398                 :           0 :     printf(NA_FORMAT, _("n/a"));
     399                 :             : #endif
     400                 :             : 
     401                 :             : /*
     402                 :             :  * Test open_sync if available
     403                 :             :  */
     404                 :           0 :     printf(LABEL_FORMAT, "open_sync");
     405                 :           0 :     fflush(stdout);
     406                 :             : 
     407                 :             : #ifdef O_SYNC
     408         [ #  # ]:           0 :     if ((tmpfile = open_direct(filename, O_RDWR | O_SYNC | PG_BINARY, 0)) == -1)
     409                 :             :     {
     410                 :           0 :         printf(NA_FORMAT, _("n/a*"));
     411                 :           0 :         fs_warning = true;
     412                 :             :     }
     413                 :             :     else
     414                 :             :     {
     415                 :           0 :         START_TIMER;
     416         [ #  # ]:           0 :         for (ops = 0; alarm_triggered == false; ops++)
     417                 :             :         {
     418         [ #  # ]:           0 :             for (writes = 0; writes < writes_per_op; writes++)
     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                 :             :                      */
     430                 :           0 :                     die("write failed");
     431                 :             :         }
     432                 :           0 :         STOP_TIMER;
     433                 :           0 :         close(tmpfile);
     434                 :             :     }
     435                 :             : #else
     436                 :             :     printf(NA_FORMAT, _("n/a"));
     437                 :             : #endif
     438                 :             : 
     439         [ #  # ]:           0 :     if (fs_warning)
     440                 :             :     {
     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                 :             :     }
     444                 :           0 : }
     445                 :             : 
     446                 :             : static void
     447                 :           0 : test_open_syncs(void)
     448                 :             : {
     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);
     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                 :             : 
     472                 :           0 :     printf(LABEL_FORMAT, msg);
     473                 :           0 :     fflush(stdout);
     474                 :             : 
     475                 :             : #ifdef O_SYNC
     476         [ #  # ]:           0 :     if ((tmpfile = open_direct(filename, O_RDWR | O_SYNC | PG_BINARY, 0)) == -1)
     477                 :           0 :         printf(NA_FORMAT, _("n/a*"));
     478                 :             :     else
     479                 :             :     {
     480                 :           0 :         START_TIMER;
     481         [ #  # ]:           0 :         for (ops = 0; alarm_triggered == false; ops++)
     482                 :             :         {
     483         [ #  # ]:           0 :             for (writes = 0; writes < 16 / writes_size; writes++)
     484                 :           0 :                 if (pg_pwrite(tmpfile,
     485                 :             :                               buf,
     486                 :           0 :                               writes_size * 1024,
     487                 :           0 :                               writes * writes_size * 1024) !=
     488         [ #  # ]:           0 :                     writes_size * 1024)
     489                 :           0 :                     die("write failed");
     490                 :             :         }
     491                 :           0 :         STOP_TIMER;
     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                 :             :      */
     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                 :             :      */
     519                 :           0 :     printf(LABEL_FORMAT, "write, fsync, close");
     520                 :           0 :     fflush(stdout);
     521                 :             : 
     522                 :           0 :     START_TIMER;
     523         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     524                 :             :     {
     525         [ #  # ]:           0 :         if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     526                 :           0 :             die("could not open output file");
     527         [ #  # ]:           0 :         if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
     528                 :           0 :             die("write failed");
     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                 :             :          */
     537         [ #  # ]:           0 :         if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     538                 :           0 :             die("could not open output file");
     539                 :           0 :         close(tmpfile);
     540                 :             :     }
     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                 :             :      */
     547                 :           0 :     printf(LABEL_FORMAT, "write, close, fsync");
     548                 :           0 :     fflush(stdout);
     549                 :             : 
     550                 :           0 :     START_TIMER;
     551         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     552                 :             :     {
     553         [ #  # ]:           0 :         if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     554                 :           0 :             die("could not open output file");
     555         [ #  # ]:           0 :         if (write(tmpfile, buf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
     556                 :           0 :             die("write failed");
     557                 :           0 :         close(tmpfile);
     558                 :             :         /* reopen file */
     559         [ #  # ]:           0 :         if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     560                 :           0 :             die("could not open output file");
     561         [ #  # ]:           0 :         if (fsync(tmpfile) != 0)
     562                 :           0 :             die("fsync failed");
     563                 :           0 :         close(tmpfile);
     564                 :             :     }
     565                 :           0 :     STOP_TIMER;
     566                 :           0 : }
     567                 :             : 
     568                 :             : static void
     569                 :           0 : test_non_sync(void)
     570                 :             : {
     571                 :             :     int         tmpfile,
     572                 :             :                 ops;
     573                 :             : 
     574                 :             :     /*
     575                 :             :      * Test a simple write without fsync
     576                 :             :      */
     577                 :           0 :     printf(_("\nNon-sync'ed %dkB writes:\n"), XLOG_BLCKSZ_K);
     578                 :           0 :     printf(LABEL_FORMAT, "write");
     579                 :           0 :     fflush(stdout);
     580                 :             : 
     581         [ #  # ]:           0 :     if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
     582                 :           0 :         die("could not open output file");
     583                 :           0 :     START_TIMER;
     584         [ #  # ]:           0 :     for (ops = 0; alarm_triggered == false; ops++)
     585                 :             :     {
     586         [ #  # ]:           0 :         if (pg_pwrite(tmpfile, buf, XLOG_BLCKSZ, 0) != XLOG_BLCKSZ)
     587                 :           0 :             die("write failed");
     588                 :             :     }
     589                 :           0 :     STOP_TIMER;
     590                 :           0 :     close(tmpfile);
     591                 :           0 : }
     592                 :             : 
     593                 :             : static void
     594                 :           0 : signal_cleanup(SIGNAL_ARGS)
     595                 :             : {
     596                 :             :     ssize_t     rc;
     597                 :             : 
     598                 :             :     /* Delete the file if it exists. Ignore errors */
     599         [ #  # ]:           0 :     if (needs_unlink)
     600                 :           0 :         unlink(filename);
     601                 :             :     /* Finish incomplete line on stdout */
     602                 :           0 :     rc = write(STDOUT_FILENO, "\n", 1);
     603                 :             :     (void) rc;                  /* silence compiler warnings */
     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
     625                 :           0 : print_elapse(struct timeval start_t, struct timeval stop_t, int ops)
     626                 :             : {
     627                 :           0 :     double      total_time = (stop_t.tv_sec - start_t.tv_sec) +
     628                 :           0 :         (stop_t.tv_usec - start_t.tv_usec) * 0.000001;
     629                 :           0 :     double      per_second = ops / total_time;
     630                 :           0 :     double      avg_op_time_us = (total_time / ops) * USECS_SEC;
     631                 :             : 
     632                 :           0 :     printf(_(OPS_FORMAT), per_second, avg_op_time_us);
     633                 :           0 : }
     634                 :             : 
     635                 :             : #ifndef WIN32
     636                 :             : static void
     637                 :           0 : process_alarm(SIGNAL_ARGS)
     638                 :             : {
     639                 :           0 :     alarm_triggered = true;
     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
        

Generated by: LCOV version 2.0-1