11/*
22 *test_fsync.c
3- *tests if fsync can be done from another process than the original write
3+ *test various fsync() methods
44 */
55
6- #include "../../include/pg_config.h"
7- #include "../../include/pg_config_os.h"
6+ #include "postgres.h"
7+
8+ #include "access/xlog_internal.h"
9+ #include "access/xlog.h"
810
911#include <sys/types.h>
1012#include <sys/stat.h>
1416#include <time.h>
1517#include <sys/time.h>
1618#include <unistd.h>
19+ #include <string.h>
1720
18- #ifdef WIN32
19- #define FSYNC_FILENAME "./test_fsync.out"
21+ /* ---------------------------------------------------------------
22+ *Copied from xlog.c. Some day this should be moved an include file.
23+ */
24+
25+ /*
26+ *Because O_DIRECT bypasses the kernel buffers, and because we never
27+ *read those buffers except during crash recovery, it is a win to use
28+ *it in all cases where we sync on each write().We could allow O_DIRECT
29+ *with fsync(), but because skipping the kernel buffer forces writes out
30+ *quickly, it seems best just to use it for O_SYNC. It is hard to imagine
31+ *how fsync() could be a win for O_DIRECT compared to O_SYNC and O_DIRECT.
32+ *Also, O_DIRECT is never enough to force data to the drives, it merely
33+ *tries to bypass the kernel cache, so we still need O_SYNC or fsync().
34+ */
35+ #ifdef O_DIRECT
36+ #define PG_O_DIRECT O_DIRECT
2037#else
21- #define FSYNC_FILENAME "/var/tmp/test_fsync.out"
38+ #define PG_O_DIRECT 0
2239#endif
2340
24- /* O_SYNC and O_FSYNC are the same */
41+ /*
42+ * This chunk of hackery attempts to determine which file sync methods
43+ * are available on the current platform, and to choose an appropriate
44+ * default method.We assume that fsync() is always available, and that
45+ * configure determined whether fdatasync() is.
46+ */
2547#if defined(O_SYNC )
26- #define OPEN_SYNC_FLAG O_SYNC
48+ #define BARE_OPEN_SYNC_FLAG O_SYNC
2749#elif defined(O_FSYNC )
28- #define OPEN_SYNC_FLAG O_FSYNC
29- #elif defined(O_DSYNC )
30- #define OPEN_DATASYNC_FLAG O_DSYNC
50+ #define BARE_OPEN_SYNC_FLAG O_FSYNC
51+ #endif
52+ #ifdef BARE_OPEN_SYNC_FLAG
53+ #define OPEN_SYNC_FLAG (BARE_OPEN_SYNC_FLAG | PG_O_DIRECT)
3154#endif
3255
56+ #if defined(O_DSYNC )
3357#if defined(OPEN_SYNC_FLAG )
34- #if defined(O_DSYNC )&& (O_DSYNC != OPEN_SYNC_FLAG )
35- #define OPEN_DATASYNC_FLAG O_DSYNC
58+ /* O_DSYNC is distinct? */
59+ #if O_DSYNC != BARE_OPEN_SYNC_FLAG
60+ #define OPEN_DATASYNC_FLAG (O_DSYNC | PG_O_DIRECT)
61+ #endif
62+ #else /* !defined(OPEN_SYNC_FLAG) */
63+ /* Win32 only has O_DSYNC */
64+ #define OPEN_DATASYNC_FLAG (O_DSYNC | PG_O_DIRECT)
65+ #endif
66+ #endif
67+
68+ #if defined(OPEN_DATASYNC_FLAG )
69+ #define DEFAULT_SYNC_METHOD_STR "open_datasync"
70+ #define DEFAULT_SYNC_METHOD SYNC_METHOD_OPEN
71+ #define DEFAULT_SYNC_FLAGBIT OPEN_DATASYNC_FLAG
72+ #elif defined(HAVE_FDATASYNC )
73+ #define DEFAULT_SYNC_METHOD_STR "fdatasync"
74+ #define DEFAULT_SYNC_METHOD SYNC_METHOD_FDATASYNC
75+ #define DEFAULT_SYNC_FLAGBIT 0
76+ #elif defined(HAVE_FSYNC_WRITETHROUGH_ONLY )
77+ #define DEFAULT_SYNC_METHOD_STR "fsync_writethrough"
78+ #define DEFAULT_SYNC_METHOD SYNC_METHOD_FSYNC_WRITETHROUGH
79+ #define DEFAULT_SYNC_FLAGBIT 0
80+ #else
81+ #define DEFAULT_SYNC_METHOD_STR "fsync"
82+ #define DEFAULT_SYNC_METHOD SYNC_METHOD_FSYNC
83+ #define DEFAULT_SYNC_FLAGBIT 0
84+ #endif
85+
86+
87+ /*
88+ * Limitation of buffer-alignment for direct IO depends on OS and filesystem,
89+ * but XLOG_BLCKSZ is assumed to be enough for it.
90+ */
91+ #ifdef O_DIRECT
92+ #define ALIGNOF_XLOG_BUFFER XLOG_BLCKSZ
93+ #else
94+ #define ALIGNOF_XLOG_BUFFER ALIGNOF_BUFFER
3695#endif
96+
97+ /* ------------ from xlog.c --------------- */
98+
99+ #ifdef WIN32
100+ #define FSYNC_FILENAME "./test_fsync.out"
101+ #else
102+ /* /tmp might be a memory file system */
103+ #define FSYNC_FILENAME "/var/tmp/test_fsync.out"
37104#endif
38105
39- #define WAL_FILE_SIZE (16 * 1024 * 1024)
106+ #define WRITE_SIZE (16 * 1024)
40107
41108void die (char * str );
42109void print_elapse (struct timeval start_t ,struct timeval elapse_t );
@@ -49,7 +116,7 @@ main(int argc, char *argv[])
49116int tmpfile ,
50117i ,
51118loops = 1000 ;
52- char * strout = (char * )malloc (WAL_FILE_SIZE ) ;
119+ char * full_buf = (char * )malloc (XLOG_SEG_SIZE ), * buf ;
53120char * filename = FSYNC_FILENAME ;
54121
55122if (argc > 2 && strcmp (argv [1 ],"-f" )== 0 )
@@ -62,23 +129,29 @@ main(int argc, char *argv[])
62129if (argc > 1 )
63130loops = atoi (argv [1 ]);
64131
65- for (i = 0 ;i < WAL_FILE_SIZE ;i ++ )
66- strout [i ]= 'a' ;
132+ for (i = 0 ;i < XLOG_SEG_SIZE ;i ++ )
133+ full_buf [i ]= 'a' ;
67134
68135if ((tmpfile = open (filename ,O_RDWR |O_CREAT ,S_IRUSR |S_IWUSR ))== -1 )
69136die ("Cannot open output file." );
70- write (tmpfile ,strout ,WAL_FILE_SIZE );
71- fsync (tmpfile );/* fsync so later fsync's don't have to do it */
137+ if (write (tmpfile ,full_buf ,XLOG_SEG_SIZE )!= XLOG_SEG_SIZE )
138+ die ("write failed" );
139+ /* fsync so later fsync's don't have to do it */
140+ if (fsync (tmpfile )!= 0 )
141+ die ("fsync failed" );
72142close (tmpfile );
73143
144+ buf = (char * )TYPEALIGN (ALIGNOF_XLOG_BUFFER ,full_buf );
145+
74146printf ("Simple write timing:\n" );
75147/* write only */
76148gettimeofday (& start_t ,NULL );
77149for (i = 0 ;i < loops ;i ++ )
78150{
79151if ((tmpfile = open (filename ,O_RDWR ))== -1 )
80152die ("Cannot open output file." );
81- write (tmpfile ,strout ,8192 );
153+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
154+ die ("write failed" );
82155close (tmpfile );
83156}
84157gettimeofday (& elapse_t ,NULL );
@@ -95,8 +168,10 @@ main(int argc, char *argv[])
95168{
96169if ((tmpfile = open (filename ,O_RDWR ))== -1 )
97170die ("Cannot open output file." );
98- write (tmpfile ,strout ,8192 );
99- fsync (tmpfile );
171+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
172+ die ("write failed" );
173+ if (fsync (tmpfile )!= 0 )
174+ die ("fsync failed" );
100175close (tmpfile );
101176if ((tmpfile = open (filename ,O_RDWR ))== -1 )
102177die ("Cannot open output file." );
@@ -114,12 +189,14 @@ main(int argc, char *argv[])
114189{
115190if ((tmpfile = open (filename ,O_RDWR ))== -1 )
116191die ("Cannot open output file." );
117- write (tmpfile ,strout ,8192 );
192+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
193+ die ("write failed" );
118194close (tmpfile );
119195/* reopen file */
120196if ((tmpfile = open (filename ,O_RDWR ))== -1 )
121197die ("Cannot open output file." );
122- fsync (tmpfile );
198+ if (fsync (tmpfile )!= 0 )
199+ die ("fsync failed" );
123200close (tmpfile );
124201}
125202gettimeofday (& elapse_t ,NULL );
@@ -135,7 +212,8 @@ main(int argc, char *argv[])
135212die ("Cannot open output file." );
136213gettimeofday (& start_t ,NULL );
137214for (i = 0 ;i < loops ;i ++ )
138- write (tmpfile ,strout ,16384 );
215+ if (write (tmpfile ,buf ,WRITE_SIZE )!= WRITE_SIZE )
216+ die ("write failed" );
139217gettimeofday (& elapse_t ,NULL );
140218close (tmpfile );
141219printf ("\tone 16k o_sync write " );
@@ -148,8 +226,10 @@ main(int argc, char *argv[])
148226gettimeofday (& start_t ,NULL );
149227for (i = 0 ;i < loops ;i ++ )
150228{
151- write (tmpfile ,strout ,8192 );
152- write (tmpfile ,strout ,8192 );
229+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
230+ die ("write failed" );
231+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
232+ die ("write failed" );
153233}
154234gettimeofday (& elapse_t ,NULL );
155235close (tmpfile );
@@ -169,7 +249,8 @@ main(int argc, char *argv[])
169249die ("Cannot open output file." );
170250gettimeofday (& start_t ,NULL );
171251for (i = 0 ;i < loops ;i ++ )
172- write (tmpfile ,strout ,8192 );
252+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
253+ die ("write failed" );
173254gettimeofday (& elapse_t ,NULL );
174255close (tmpfile );
175256printf ("\topen o_dsync, write " );
@@ -181,7 +262,8 @@ main(int argc, char *argv[])
181262die ("Cannot open output file." );
182263gettimeofday (& start_t ,NULL );
183264for (i = 0 ;i < loops ;i ++ )
184- write (tmpfile ,strout ,8192 );
265+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
266+ die ("write failed" );
185267gettimeofday (& elapse_t ,NULL );
186268close (tmpfile );
187269printf ("\topen o_sync, write " );
@@ -199,7 +281,8 @@ main(int argc, char *argv[])
199281gettimeofday (& start_t ,NULL );
200282for (i = 0 ;i < loops ;i ++ )
201283{
202- write (tmpfile ,strout ,8192 );
284+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
285+ die ("write failed" );
203286fdatasync (tmpfile );
204287}
205288gettimeofday (& elapse_t ,NULL );
@@ -217,8 +300,10 @@ main(int argc, char *argv[])
217300gettimeofday (& start_t ,NULL );
218301for (i = 0 ;i < loops ;i ++ )
219302{
220- write (tmpfile ,strout ,8192 );
221- fsync (tmpfile );
303+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
304+ die ("write failed" );
305+ if (fsync (tmpfile )!= 0 )
306+ die ("fsync failed" );
222307}
223308gettimeofday (& elapse_t ,NULL );
224309close (tmpfile );
@@ -235,8 +320,10 @@ main(int argc, char *argv[])
235320gettimeofday (& start_t ,NULL );
236321for (i = 0 ;i < loops ;i ++ )
237322{
238- write (tmpfile ,strout ,8192 );
239- write (tmpfile ,strout ,8192 );
323+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
324+ die ("write failed" );
325+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
326+ die ("write failed" );
240327}
241328gettimeofday (& elapse_t ,NULL );
242329close (tmpfile );
@@ -254,8 +341,10 @@ main(int argc, char *argv[])
254341gettimeofday (& start_t ,NULL );
255342for (i = 0 ;i < loops ;i ++ )
256343{
257- write (tmpfile ,strout ,8192 );
258- write (tmpfile ,strout ,8192 );
344+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
345+ die ("write failed" );
346+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
347+ die ("write failed" );
259348}
260349gettimeofday (& elapse_t ,NULL );
261350close (tmpfile );
@@ -271,8 +360,10 @@ main(int argc, char *argv[])
271360gettimeofday (& start_t ,NULL );
272361for (i = 0 ;i < loops ;i ++ )
273362{
274- write (tmpfile ,strout ,8192 );
275- write (tmpfile ,strout ,8192 );
363+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
364+ die ("write failed" );
365+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
366+ die ("write failed" );
276367fdatasync (tmpfile );
277368}
278369gettimeofday (& elapse_t ,NULL );
@@ -290,16 +381,20 @@ main(int argc, char *argv[])
290381gettimeofday (& start_t ,NULL );
291382for (i = 0 ;i < loops ;i ++ )
292383{
293- write (tmpfile ,strout ,8192 );
294- write (tmpfile ,strout ,8192 );
295- fsync (tmpfile );
384+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
385+ die ("write failed" );
386+ if (write (tmpfile ,buf ,WRITE_SIZE /2 )!= WRITE_SIZE /2 )
387+ die ("write failed" );
388+ if (fsync (tmpfile )!= 0 )
389+ die ("fsync failed" );
296390}
297391gettimeofday (& elapse_t ,NULL );
298392close (tmpfile );
299393printf ("\twrite, fsync, " );
300394print_elapse (start_t ,elapse_t );
301395printf ("\n" );
302396
397+ free (full_buf );
303398unlink (filename );
304399
305400return 0 ;