From 65d30cc9c36b782c704daeb4b3f75cdbc7bff680 Mon Sep 17 00:00:00 2001 From: Raymond Lu Date: Tue, 10 Oct 2006 15:07:16 -0500 Subject: [svn-r12739] Added Direct I/O driver to VFD. It's only supported by SGI Altix (cobalt). There's a configure option --enable-direct-vfd/--disable-direct-vfd to enable/disable Direct I/O support. The default is enabled. There's a small test in test/vfd.c. Another way to test it is to set environment variable HDF5_DRIVER to "direct" and run "make check" in the test/ directory. There'll be some further improvement in the following checkin including allowing user to provide memory boundary value, file block size, and copying buffer size. --- MANIFEST | 2 + configure | 151 ++++++-- configure.in | 39 ++ src/H5F.c | 1 + src/H5FD.c | 4 + src/H5FDdirect.c | 989 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/H5FDdirect.h | 47 +++ src/H5FLprivate.h | 2 +- src/H5Fprivate.h | 2 +- src/H5Lexternal.c | 2 +- src/H5config.h.in | 3 + src/Makefile.am | 6 +- src/Makefile.in | 9 +- src/hdf5.h | 1 + test/h5test.c | 5 + test/reserved.c | 1 + test/vfd.c | 84 +++++ tools/h5dump/h5dump.c | 14 +- 18 files changed, 1317 insertions(+), 45 deletions(-) create mode 100644 src/H5FDdirect.c create mode 100644 src/H5FDdirect.h diff --git a/MANIFEST b/MANIFEST index 8d19fca..8bfa9c3 100644 --- a/MANIFEST +++ b/MANIFEST @@ -466,6 +466,8 @@ ./src/H5FD.c ./src/H5FDcore.c ./src/H5FDcore.h +./src/H5FDdirect.c +./src/H5FDdirect.h ./src/H5FDfamily.c ./src/H5FDfamily.h ./src/H5FDlog.c diff --git a/configure b/configure index cbec5b3..32f2bad 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Id: configure.in 12700 2006-10-02 10:24:03Z koziol . +# From configure.in Id: configure.in 12715 2006-10-03 22:41:34Z jlaird . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for HDF5 1.8.0-alpha6. # @@ -1082,6 +1082,8 @@ Optional Features: specify a comma-separated list of filters or the word no. The default is all internal I/O filters. --enable-stream-vfd Build the Stream Virtual File Driver [default=yes] + --enable-direct-vfd Build the Direct I/O Virtual File Driver + [default=yes] --enable-dconv-exception if exception handling functions is checked during data conversions [default=yes] @@ -3519,7 +3521,7 @@ fi # Provide some information about the compiler. -echo "$as_me:3522:" \ +echo "$as_me:3524:" \ "checking for Fortran compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 @@ -3814,7 +3816,7 @@ _ACEOF # flags. ac_save_FFLAGS=$FCFLAGS FCFLAGS="$FCFLAGS $ac_verb" -(eval echo $as_me:3817: \"$ac_link\") >&5 +(eval echo $as_me:3819: \"$ac_link\") >&5 ac_fc_v_output=`eval $ac_link 5>&1 2>&1 | grep -v 'Driving:'` echo "$ac_fc_v_output" >&5 FCFLAGS=$ac_save_FFLAGS @@ -3892,7 +3894,7 @@ _ACEOF # flags. ac_save_FFLAGS=$FCFLAGS FCFLAGS="$FCFLAGS $ac_cv_prog_fc_v" -(eval echo $as_me:3895: \"$ac_link\") >&5 +(eval echo $as_me:3897: \"$ac_link\") >&5 ac_fc_v_output=`eval $ac_link 5>&1 2>&1 | grep -v 'Driving:'` echo "$ac_fc_v_output" >&5 FCFLAGS=$ac_save_FFLAGS @@ -6665,7 +6667,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 6668 "configure"' > conftest.$ac_ext + echo '#line 6670 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7795,7 +7797,7 @@ fi # Provide some information about the compiler. -echo "$as_me:7798:" \ +echo "$as_me:7800:" \ "checking for Fortran 77 compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 @@ -8864,11 +8866,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:8867: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8869: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:8871: \$? = $ac_status" >&5 + echo "$as_me:8873: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -9119,11 +9121,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:9122: $lt_compile\"" >&5) + (eval echo "\"\$as_me:9124: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:9126: \$? = $ac_status" >&5 + echo "$as_me:9128: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -9179,11 +9181,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:9182: $lt_compile\"" >&5) + (eval echo "\"\$as_me:9184: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:9186: \$? = $ac_status" >&5 + echo "$as_me:9188: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -11451,7 +11453,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:13790: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:13792: \$? = $ac_status" >&5 + echo "$as_me:13794: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -13845,11 +13847,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:13848: $lt_compile\"" >&5) + (eval echo "\"\$as_me:13850: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:13852: \$? = $ac_status" >&5 + echo "$as_me:13854: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -15264,7 +15266,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:16222: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:16224: \$? = $ac_status" >&5 + echo "$as_me:16226: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -16277,11 +16279,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:16280: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16282: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:16284: \$? = $ac_status" >&5 + echo "$as_me:16286: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -18333,11 +18335,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:18336: $lt_compile\"" >&5) + (eval echo "\"\$as_me:18338: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:18340: \$? = $ac_status" >&5 + echo "$as_me:18342: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -18588,11 +18590,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:18591: $lt_compile\"" >&5) + (eval echo "\"\$as_me:18593: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:18595: \$? = $ac_status" >&5 + echo "$as_me:18597: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -18648,11 +18650,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:18651: $lt_compile\"" >&5) + (eval echo "\"\$as_me:18653: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:18655: \$? = $ac_status" >&5 + echo "$as_me:18657: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -20920,7 +20922,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5 +echo $ECHO_N "checking for Direct Virtual File Driver support... $ECHO_C" >&6 + +# Check whether --enable-direct-vfd or --disable-direct-vfd was given. +if test "${enable_direct_vfd+set}" = set; then + enableval="$enable_direct_vfd" + DIRECT_VFD=$enableval +else + DIRECT_VFD=yes +fi; + +if test "$DIRECT_VFD" = "yes"; then + if test "${hdf5_direct_io+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run test program while cross compiling +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #include + #include + #include + int main(void) + { + int fid; + if((fid=open("tst_file", O_CREAT | O_TRUNC | O_DIRECT, 0755))<0) + exit(1); + close(fid); + remove("tst_file"); + exit (0); + } +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + hdf5_direct_io=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +hdf5_direct_io=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi + + + if test ${hdf5_direct_io} = "yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DIRECT 1 +_ACEOF + + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + fi +else + echo "$as_me:$LINENO: result: suppressed" >&5 +echo "${ECHO_T}suppressed" >&6 +fi + echo "$as_me:$LINENO: checking whether exception handling functions is checked during data conversions" >&5 echo $ECHO_N "checking whether exception handling functions is checked during data conversions... $ECHO_C" >&6 # Check whether --enable-dconv-exception or --disable-dconv-exception was given. diff --git a/configure.in b/configure.in index f14cf56..b141e2c 100644 --- a/configure.in +++ b/configure.in @@ -2572,6 +2572,45 @@ if test "$STREAM_VFD" = "yes"; then fi dnl ---------------------------------------------------------------------- +dnl Check if Direct I/O driver is wanted by --enable-direct-vfd +dnl + +AC_MSG_CHECKING([for Direct Virtual File Driver support]) + +AC_ARG_ENABLE([direct-vfd], + [AC_HELP_STRING([--enable-direct-vfd], + [Build the Direct I/O Virtual File Driver + [default=yes]])], + [DIRECT_VFD=$enableval], [DIRECT_VFD=yes]) + +if test "$DIRECT_VFD" = "yes"; then + AC_CACHE_VAL([hdf5_direct_io], + [AC_TRY_RUN([ + #include + #include + #include + int main(void) + { + int fid; + if((fid=open("tst_file", O_CREAT | O_TRUNC | O_DIRECT, 0755))<0) + exit(1); + close(fid); + remove("tst_file"); + exit (0); + }], [hdf5_direct_io=yes], [hdf5_direct_io=no],)]) + + if test ${hdf5_direct_io} = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_DIRECT], [1], + [Define if the direct I/O virtual file driver should be compiled]) + else + AC_MSG_RESULT([no]) + fi +else + AC_MSG_RESULT([suppressed]) +fi + +dnl ---------------------------------------------------------------------- dnl Decide whether the presence of user's exception handling functions is dnl checked and data conversion exceptions are returned. This is mainly dnl for the speed optimization of hard conversions. Soft conversions can diff --git a/src/H5F.c b/src/H5F.c index a12c97d..35787f7 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -41,6 +41,7 @@ #include "H5FDsec2.h" /*Posix unbuffered I/O */ #include "H5FDstdio.h" /* Standard C buffered I/O */ #include "H5FDstream.h" /*in-memory files streamed via sockets */ +#include "H5FDdirect.h" /*Linux direct I/O */ /* Struct only used by functions H5F_get_objects and H5F_get_objects_cb */ typedef struct H5F_olist_t { diff --git a/src/H5FD.c b/src/H5FD.c index f5c7a85..952bad9 100644 --- a/src/H5FD.c +++ b/src/H5FD.c @@ -43,6 +43,7 @@ #include "H5FDsec2.h" /* POSIX unbuffered file I/O */ #include "H5FDstdio.h" /* Standard C buffered I/O */ #include "H5FDstream.h" /* In-memory files streamed via sockets */ +#include "H5FDdirect.h" /* Direct file I/O */ #include "H5FLprivate.h" /* Free lists */ #include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ @@ -161,6 +162,9 @@ H5FD_term_interface(void) /* Reset the VFL drivers, if they've been closed */ if(H5I_nmembers(H5I_VFL)==0) { H5FD_sec2_term(); +#ifdef H5_HAVE_DIRECT + H5FD_direct_term(); +#endif H5FD_log_term(); H5FD_stdio_term(); H5FD_family_term(); diff --git a/src/H5FDdirect.c b/src/H5FDdirect.c new file mode 100644 index 0000000..54283b5 --- /dev/null +++ b/src/H5FDdirect.c @@ -0,0 +1,989 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Purpose: The Direct I/O file driver forces the data to be written to + * the file directly without being copied into system kernel + * buffer. The main system support this feature is Linux. + */ + +/* Interface initialization */ +#define H5_INTERFACE_INIT_FUNC H5FD_direct_init_interface + +/* For system function posix_memalign */ +#define _XOPEN_SOURCE 600 + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fprivate.h" /* File access */ +#include "H5FDprivate.h" /* File drivers */ +#include "H5FDdirect.h" /* Direct file driver */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Pprivate.h" /* Property lists */ + +#ifdef H5_HAVE_DIRECT + +/* The driver identification number, initialized at runtime */ +static hid_t H5FD_DIRECT_g = 0; + +/* File operations */ +#define OP_UNKNOWN 0 +#define OP_READ 1 +#define OP_WRITE 2 + +/* + * The description of a file belonging to this driver. The `eoa' and `eof' + * determine the amount of hdf5 address space in use and the high-water mark + * of the file (the current size of the underlying Unix file). The `pos' + * value is used to eliminate file position updates when they would be a + * no-op. Unfortunately we've found systems that use separate file position + * indicators for reading and writing so the lseek can only be eliminated if + * the current operation is the same as the previous operation. When opening + * a file the `eof' will be set to the current file size, `eoa' will be set + * to zero, `pos' will be set to H5F_ADDR_UNDEF (as it is when an error + * occurs), and `op' will be set to H5F_OP_UNKNOWN. + */ +typedef struct H5FD_direct_t { + H5FD_t pub; /*public stuff, must be first */ + int fd; /*the unix file */ + haddr_t eoa; /*end of allocated region */ + haddr_t eof; /*end of file; current file size*/ + haddr_t pos; /*current file I/O position */ + int op; /*last operation */ +#ifndef WIN32 + /* + * On most systems the combination of device and i-node number uniquely + * identify a file. + */ + dev_t device; /*file device number */ +#ifdef H5_VMS + ino_t inode[3]; /*file i-node number */ +#else + ino_t inode; /*file i-node number */ +#endif /*H5_VMS*/ +#else + /* + * On WIN32 the low-order word of a unique identifier associated with the + * file and the volume serial number uniquely identify a file. This number + * (which, both? -rpm) may change when the system is restarted or when the + * file is opened. After a process opens a file, the identifier is + * constant until the file is closed. An application can use this + * identifier and the volume serial number to determine whether two + * handles refer to the same file. + */ + DWORD fileindexlo; + DWORD fileindexhi; +#endif +} H5FD_direct_t; + +/* + * This driver supports systems that have the lseek64() function by defining + * some macros here so we don't have to have conditional compilations later + * throughout the code. + * + * file_offset_t: The datatype for file offsets, the second argument of + * the lseek() or lseek64() call. + * + * file_seek: The function which adjusts the current file position, + * either lseek() or lseek64(). + */ +/* adding for windows NT file system support. */ + +#ifdef H5_HAVE_LSEEK64 +# define file_offset_t off64_t +# define file_seek lseek64 +# define file_truncate ftruncate64 +#elif defined (WIN32) && !defined(__MWERKS__) +# /*MSVC*/ +# define file_offset_t __int64 +# define file_seek _lseeki64 +# define file_truncate _chsize +#else +# define file_offset_t off_t +# define file_seek lseek +# define file_truncate HDftruncate +#endif + +/* + * These macros check for overflow of various quantities. These macros + * assume that file_offset_t is signed and haddr_t and size_t are unsigned. + * + * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t' + * is too large to be represented by the second argument + * of the file seek function. + * + * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too + * large to be represented by the `size_t' type. + * + * REGION_OVERFLOW: Checks whether an address and size pair describe data + * which can be addressed entirely by the second + * argument of the file seek function. + */ +#define MAXADDR (((haddr_t)1<<(8*sizeof(file_offset_t)-1))-1) +#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || \ + ((A) & ~(haddr_t)MAXADDR)) +#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR) +#define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \ + HADDR_UNDEF==(A)+(Z) || \ + (file_offset_t)((A)+(Z))<(file_offset_t)(A)) + +/* Hard-code file system block size */ +#define FBSIZE 4096 + +/* Prototypes */ +static H5FD_t *H5FD_direct_open(const char *name, unsigned flags, hid_t fapl_id, + haddr_t maxaddr); +static herr_t H5FD_direct_close(H5FD_t *_file); +static int H5FD_direct_cmp(const H5FD_t *_f1, const H5FD_t *_f2); +static herr_t H5FD_direct_query(const H5FD_t *_f1, unsigned long *flags); +static haddr_t H5FD_direct_get_eoa(const H5FD_t *_file); +static herr_t H5FD_direct_set_eoa(H5FD_t *_file, haddr_t addr); +static haddr_t H5FD_direct_get_eof(const H5FD_t *_file); +static herr_t H5FD_direct_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle); +static herr_t H5FD_direct_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, + size_t size, void *buf); +static herr_t H5FD_direct_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, + size_t size, const void *buf); +static herr_t H5FD_direct_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing); + +static const H5FD_class_t H5FD_direct_g = { + "direct", /*name */ + MAXADDR, /*maxaddr */ + H5F_CLOSE_WEAK, /* fc_degree */ + NULL, /*sb_size */ + NULL, /*sb_encode */ + NULL, /*sb_decode */ + 0, /*fapl_size */ + NULL, /*fapl_get */ + NULL, /*fapl_copy */ + NULL, /*fapl_free */ + 0, /*dxpl_size */ + NULL, /*dxpl_copy */ + NULL, /*dxpl_free */ + H5FD_direct_open, /*open */ + H5FD_direct_close, /*close */ + H5FD_direct_cmp, /*cmp */ + H5FD_direct_query, /*query */ + NULL, /*alloc */ + NULL, /*free */ + H5FD_direct_get_eoa, /*get_eoa */ + H5FD_direct_set_eoa, /*set_eoa */ + H5FD_direct_get_eof, /*get_eof */ + H5FD_direct_get_handle, /*get_handle */ + H5FD_direct_read, /*read */ + H5FD_direct_write, /*write */ + H5FD_direct_flush, /*flush */ + NULL, /*lock */ + NULL, /*unlock */ + H5FD_FLMAP_SINGLE /*fl_map */ +}; + +/* Declare a free list to manage the H5FD_direct_t struct */ +H5FL_DEFINE_STATIC(H5FD_direct_t); + + +/*-------------------------------------------------------------------------- +NAME + H5FD_direct_init_interface -- Initialize interface-specific information +USAGE + herr_t H5FD_direct_init_interface() + +RETURNS + Non-negative on success/Negative on failure +DESCRIPTION + Initializes any interface-specific data or routines. (Just calls + H5FD_direct_init currently). + +--------------------------------------------------------------------------*/ +static herr_t +H5FD_direct_init_interface(void) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_direct_init_interface) + + FUNC_LEAVE_NOAPI(H5FD_direct_init()) +} /* H5FD_direct_init_interface() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_init + * + * Purpose: Initialize this driver by registering the driver with the + * library. + * + * Return: Success: The driver ID for the direct driver. + * + * Failure: Negative. + * + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +hid_t +H5FD_direct_init(void) +{ + hid_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_direct_init, FAIL) + + if (H5I_VFL!=H5I_get_type(H5FD_DIRECT_g)) + H5FD_DIRECT_g = H5FD_register(&H5FD_direct_g,sizeof(H5FD_class_t)); + + /* Set return value */ + ret_value=H5FD_DIRECT_g; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*--------------------------------------------------------------------------- + * Function: H5FD_direct_term + * + * Purpose: Shut down the VFD + * + * Return: + * + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Modification: + * + *--------------------------------------------------------------------------- + */ +void +H5FD_direct_term(void) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FD_direct_term) + + /* Reset VFL ID */ + H5FD_DIRECT_g=0; + + FUNC_LEAVE_NOAPI_VOID +} /* end H5FD_direct_term() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pset_fapl_direct + * + * Purpose: Modify the file access property list to use the H5FD_DIRECT + * driver defined in this source file. There are no driver + * specific properties. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_fapl_direct(hid_t fapl_id) +{ + H5P_genplist_t *plist; /* Property list pointer */ + herr_t ret_value; + + FUNC_ENTER_API(H5Pset_fapl_direct, FAIL) + H5TRACE1("e","i",fapl_id); + + if(NULL == (plist = H5P_object_verify(fapl_id,H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") + + ret_value= H5P_set_driver(plist, H5FD_DIRECT, NULL); + +done: + FUNC_LEAVE_API(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_open + * + * Purpose: Create and/or opens a Unix file for direct I/O as an HDF5 file. + * + * Return: Success: A pointer to a new file data structure. The + * public fields will be initialized by the + * caller, which is always H5FD_open(). + * + * Failure: NULL + * + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static H5FD_t * +H5FD_direct_open(const char *name, unsigned flags, hid_t UNUSED fapl_id, + haddr_t maxaddr) +{ + int o_flags; + int fd=(-1); + H5FD_direct_t *file=NULL; +#ifdef WIN32 + HFILE filehandle; + struct _BY_HANDLE_FILE_INFORMATION fileinfo; +#endif + h5_stat_t sb; + H5FD_t *ret_value; + + FUNC_ENTER_NOAPI(H5FD_direct_open, NULL) + + /* Sanity check on file offsets */ + assert(sizeof(file_offset_t)>=sizeof(size_t)); + + /* Check arguments */ + if (!name || !*name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name") + if (0==maxaddr || HADDR_UNDEF==maxaddr) + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr") + if (ADDR_OVERFLOW(maxaddr)) + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr") + + /* Build the open flags */ + o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY; + if (H5F_ACC_TRUNC & flags) o_flags |= O_TRUNC; + if (H5F_ACC_CREAT & flags) o_flags |= O_CREAT; + if (H5F_ACC_EXCL & flags) o_flags |= O_EXCL; + + /* Flag for Direct I/O */ + o_flags |= O_DIRECT; + + /* Open the file */ + if ((fd=HDopen(name, o_flags, 0666))<0) + HSYS_GOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file") + + if (HDfstat(fd, &sb)<0) + HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file") + + /* Create the new file struct */ + if (NULL==(file=H5FL_CALLOC(H5FD_direct_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct") + + file->fd = fd; + H5_ASSIGN_OVERFLOW(file->eof,sb.st_size,h5_stat_size_t,haddr_t); + file->pos = HADDR_UNDEF; + file->op = OP_UNKNOWN; +#ifdef WIN32 + filehandle = _get_osfhandle(fd); + (void)GetFileInformationByHandle((HANDLE)filehandle, &fileinfo); + file->fileindexhi = fileinfo.nFileIndexHigh; + file->fileindexlo = fileinfo.nFileIndexLow; +#else + file->device = sb.st_dev; +#ifdef H5_VMS + file->inode[0] = sb.st_ino[0]; + file->inode[1] = sb.st_ino[1]; + file->inode[2] = sb.st_ino[2]; +#else + file->inode = sb.st_ino; +#endif /*H5_VMS*/ + +#endif + + /* Set return value */ + ret_value=(H5FD_t*)file; + +done: + if(ret_value==NULL) { + if(fd>=0) + HDclose(fd); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_close + * + * Purpose: Closes the file. + * + * Return: Success: 0 + * + * Failure: -1, file not closed. + * + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_direct_close(H5FD_t *_file) +{ + H5FD_direct_t *file = (H5FD_direct_t*)_file; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_direct_close, FAIL) + + if (HDclose(file->fd)<0) + HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file") + + H5FL_FREE(H5FD_direct_t,file); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_cmp + * + * Purpose: Compares two files belonging to this driver using an + * arbitrary (but consistent) ordering. + * + * Return: Success: A value like strcmp() + * + * Failure: never fails (arguments were checked by the + * caller). + * + * Programmer: Raymond Lu + * Thursday, 21 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +H5FD_direct_cmp(const H5FD_t *_f1, const H5FD_t *_f2) +{ + const H5FD_direct_t *f1 = (const H5FD_direct_t*)_f1; + const H5FD_direct_t *f2 = (const H5FD_direct_t*)_f2; + int ret_value=0; + + FUNC_ENTER_NOAPI(H5FD_direct_cmp, H5FD_VFD_DEFAULT) + +#ifdef WIN32 + if (f1->fileindexhi < f2->fileindexhi) HGOTO_DONE(-1) + if (f1->fileindexhi > f2->fileindexhi) HGOTO_DONE(1) + + if (f1->fileindexlo < f2->fileindexlo) HGOTO_DONE(-1) + if (f1->fileindexlo > f2->fileindexlo) HGOTO_DONE(1) + +#else +#ifdef H5_DEV_T_IS_SCALAR + if (f1->device < f2->device) HGOTO_DONE(-1) + if (f1->device > f2->device) HGOTO_DONE(1) +#else /* H5_DEV_T_IS_SCALAR */ + /* If dev_t isn't a scalar value on this system, just use memcmp to + * determine if the values are the same or not. The actual return value + * shouldn't really matter... + */ + if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))<0) HGOTO_DONE(-1) + if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t))>0) HGOTO_DONE(1) +#endif /* H5_DEV_T_IS_SCALAR */ + +#ifndef H5_VMS + if (f1->inode < f2->inode) HGOTO_DONE(-1) + if (f1->inode > f2->inode) HGOTO_DONE(1) +#else + if(HDmemcmp(&(f1->inode),&(f2->inode),3*sizeof(ino_t))<0) HGOTO_DONE(-1) + if(HDmemcmp(&(f1->inode),&(f2->inode),3*sizeof(ino_t))>0) HGOTO_DONE(1) +#endif /*H5_VMS*/ + +#endif + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_query + * + * Purpose: Set the flags that this VFL driver is capable of supporting. + * (listed in H5FDpublic.h) + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Raymond Lu + * Thursday, 21 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_direct_query(const H5FD_t UNUSED * _f, unsigned long *flags /* out */) +{ + herr_t ret_value=SUCCEED; + + FUNC_ENTER_NOAPI(H5FD_direct_query, FAIL) + + /* Set the VFL feature flags that this driver supports */ + if(flags) { + *flags = 0; + *flags|=H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */ + *flags|=H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */ + *flags|=H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */ + *flags|=H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */ + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_get_eoa + * + * Purpose: Gets the end-of-address marker for the file. The EOA marker + * is the first address past the last byte allocated in the + * format address space. + * + * Return: Success: The end-of-address marker. + * + * Failure: HADDR_UNDEF + * + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_direct_get_eoa(const H5FD_t *_file) +{ + const H5FD_direct_t *file = (const H5FD_direct_t*)_file; + haddr_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_direct_get_eoa, HADDR_UNDEF) + + /* Set return value */ + ret_value=file->eoa; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_set_eoa + * + * Purpose: Set the end-of-address marker for the file. This function is + * called shortly after an existing HDF5 file is opened in order + * to tell the driver where the end of the HDF5 data is located. + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_direct_set_eoa(H5FD_t *_file, haddr_t addr) +{ + H5FD_direct_t *file = (H5FD_direct_t*)_file; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_direct_set_eoa, FAIL) + + file->eoa = addr; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_get_eof + * + * Purpose: Returns the end-of-file marker, which is the greater of + * either the Unix end-of-file or the HDF5 end-of-address + * markers. + * + * Return: Success: End of file address, the first address past + * the end of the "file", either the Unix file + * or the HDF5 file. + * + * Failure: HADDR_UNDEF + * + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_direct_get_eof(const H5FD_t *_file) +{ + const H5FD_direct_t *file = (const H5FD_direct_t*)_file; + haddr_t ret_value; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_direct_get_eof, HADDR_UNDEF) + + /* Set return value */ + ret_value=MAX(file->eof, file->eoa); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_diect_get_handle + * + * Purpose: Returns the file handle of direct file driver. + * + * Returns: Non-negative if succeed or negative if fails. + * + * Programmer: Raymond Lu + * 21 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_direct_get_handle(H5FD_t *_file, hid_t UNUSED fapl, void** file_handle) +{ + H5FD_direct_t *file = (H5FD_direct_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5FD_direct_get_handle, FAIL) + + if(!file_handle) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid") + *file_handle = &(file->fd); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_read + * + * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR + * into buffer BUF according to data transfer properties in + * DXPL_ID. + * + * Return: Success: Zero. Result is stored in caller-supplied + * buffer BUF. + * + * Failure: -1, Contents of buffer BUF are undefined. + * + * Programmer: Raymond Lu + * Thursday, 21 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_direct_read(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, haddr_t addr, + size_t size, void *buf/*out*/) +{ + H5FD_direct_t *file = (H5FD_direct_t*)_file; + ssize_t nbytes; + size_t alloc_size, mem_page_size; + void *copy_buf, *p1, *p2; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_direct_read, FAIL) + + assert(file && file->pub.cls); + assert(buf); + + /* Check for overflow conditions */ + if (HADDR_UNDEF==addr) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined") + if (REGION_OVERFLOW(addr, size)) + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow") + if (addr+size>file->eoa) + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow") + + /* memory page size needed for the Direct IO option. Make a bigger + * buffer for aligned I/O. */ + mem_page_size = getpagesize(); + alloc_size = (size / FBSIZE + 1) * FBSIZE + FBSIZE; + if (posix_memalign(©_buf, mem_page_size, alloc_size) != 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "posix_memalign failed") + memset(copy_buf, 0, alloc_size); + + /* look for the aligned position for reading the data */ + if(file_seek(file->fd, (file_offset_t)(addr - addr % FBSIZE), SEEK_SET) < 0) + HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position") + + /* + * Read the aligned data in file first, being careful of interrupted system calls, + * partial results, and the end of the file. + */ + p1 = copy_buf; + while(alloc_size > 0) { + do { + nbytes = HDread(file->fd, p1, alloc_size); + } while(-1==nbytes && EINTR==errno); + + if (-1==nbytes) /* error */ + HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed") + if (0==nbytes) { + /* end of file but not end of format address space */ + break; + } else { + assert(nbytes>0); + assert((size_t)nbytes<=alloc_size); + H5_CHECK_OVERFLOW(nbytes,ssize_t,size_t); + H5_CHECK_OVERFLOW(nbytes,ssize_t,haddr_t); + alloc_size -= (size_t)nbytes; + p1 = (unsigned char*)p1 + nbytes; + } + } + + /*look for the right position to copy the data and copy the data + *to the original buffer.*/ + p2 = (unsigned char*)copy_buf + addr % FBSIZE; + memcpy(buf, p2, size); + + /*update address and buffer*/ + addr += (haddr_t)size; + buf = (unsigned char*)buf + size; + + /* Update current position */ + file->pos = addr; + file->op = OP_READ; + + if(((addr % FBSIZE != 0) || (size % FBSIZE != 0)) && copy_buf) + HDfree(copy_buf); + +done: + if(ret_value<0) { + /* Reset last file I/O information */ + file->pos = HADDR_UNDEF; + file->op = OP_UNKNOWN; + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_write + * + * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR + * from buffer BUF according to data transfer properties in + * DXPL_ID. + * + * Return: Success: Zero + * + * Failure: -1 + * + * Programmer: Raymond Lu + * Thursday, 21 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_direct_write(H5FD_t *_file, H5FD_mem_t UNUSED type, hid_t UNUSED dxpl_id, haddr_t addr, + size_t size, const void *buf) +{ + H5FD_direct_t *file = (H5FD_direct_t*)_file; + ssize_t nbytes; + size_t alloc_size, mem_page_size, dup_size; + void *copy_buf, *p1, *p2; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_direct_write, FAIL) + + assert(file && file->pub.cls); + assert(buf); + + /* Check for overflow conditions */ + if (HADDR_UNDEF==addr) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined") + if (REGION_OVERFLOW(addr, size)) + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow") + if (addr+size>file->eoa) + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow") + + /* memory page size needed for the Direct IO option. Make a + * bigger buffer for aligned I/O + */ + mem_page_size = getpagesize(); + alloc_size = (size / FBSIZE + 1) * FBSIZE + FBSIZE; + if (posix_memalign(©_buf, mem_page_size, alloc_size) != 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "posix_memalign failed") + memset(copy_buf, 0, alloc_size); + + /* look for the right position for reading the data */ + if(file_seek(file->fd, (file_offset_t)(addr - addr % FBSIZE), SEEK_SET) < 0) + HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position") + + /* + * Read the aligned data first, being careful of interrupted system calls, + * partial results, and the end of the file. + */ + p2 = copy_buf; + dup_size = alloc_size; + while(dup_size > 0) { + do { + nbytes = read(file->fd, p2, dup_size); + } while (-1==nbytes && EINTR==errno); + if (-1==nbytes) /* error */ + HSYS_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed") + if (0==nbytes) { + /* end of file but not end of format address space */ + break; + } else { + assert(nbytes>0); + assert((size_t)nbytes<=dup_size); + H5_CHECK_OVERFLOW(nbytes,ssize_t,size_t); + H5_CHECK_OVERFLOW(nbytes,ssize_t,haddr_t); + dup_size -= (size_t)nbytes; + p2 = (unsigned char*)p2 + nbytes; + } + } + + /*append or copy the data to be written to the aligned buffer.*/ + p1 = (unsigned char*)copy_buf + addr % FBSIZE; + memcpy(p1, buf, size); + + /*look for the aligned position for writing the data*/ + if(file_seek(file->fd, (file_offset_t)(addr - addr % FBSIZE), SEEK_SET) < 0) + HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position") + + /* + * Write the data, being careful of interrupted system calls and partial write. + * It doesn't truncate the extra data introduced by alignment because that step + * is done in H5FD_direct_flush. + */ + p2 = copy_buf; + while (alloc_size>0) { + do { + nbytes = HDwrite(file->fd, p2, alloc_size); + } while (-1==nbytes && EINTR==errno); + + if (-1==nbytes) { /* error */ + HSYS_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") + } + assert(nbytes>0); + assert((size_t)nbytes<=alloc_size); + H5_CHECK_OVERFLOW(nbytes,ssize_t,size_t); + H5_CHECK_OVERFLOW(nbytes,ssize_t,haddr_t); + alloc_size -= (size_t)nbytes; + p2 = (unsigned char*)p2 + nbytes; + } + + /*Update the address and size*/ + addr += (haddr_t)size; + buf = (const char*)buf + size; + + /* Update current position and eof */ + file->pos = addr; + file->op = OP_WRITE; + if (file->pos>file->eof) + file->eof = file->pos; + + if(((addr % FBSIZE != 0) || (size % FBSIZE != 0)) && copy_buf) + HDfree(copy_buf); + +done: + if(ret_value<0) { + /* Reset last file I/O information */ + file->pos = HADDR_UNDEF; + file->op = OP_UNKNOWN; + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_direct_flush + * + * Purpose: Makes sure that the true file size is the same (or larger) + * than the end-of-address. + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Raymond Lu + * Thursday, 21 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_direct_flush(H5FD_t *_file, hid_t UNUSED dxpl_id, unsigned UNUSED closing) +{ + H5FD_direct_t *file = (H5FD_direct_t*)_file; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(H5FD_direct_flush, FAIL) + + assert(file); + + /* Extend the file to make sure it's large enough */ + if (file->eoa!=file->eof) { +#ifdef WIN32 + HFILE filehandle; /* Windows file handle */ + LARGE_INTEGER li; /* 64-bit integer for SetFilePointer() call */ + + /* Map the posix file handle to a Windows file handle */ + filehandle = _get_osfhandle(file->fd); + + /* Translate 64-bit integers into form Windows wants */ + /* [This algorithm is from the Windows documentation for SetFilePointer()] */ + li.QuadPart = (LONGLONG)file->eoa; + (void)SetFilePointer((HANDLE)filehandle,li.LowPart,&li.HighPart,FILE_BEGIN); + if(SetEndOfFile((HANDLE)filehandle)==0) + HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly") +#else /* WIN32 */ + if (-1==file_truncate(file->fd, (file_offset_t)file->eoa)) + HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly") +#endif /* WIN32 */ + + /* Update the eof value */ + file->eof = file->eoa; + + /* Reset last file I/O information */ + file->pos = HADDR_UNDEF; + file->op = OP_UNKNOWN; + } else { + /*Even though eof is equal to eoa, file is still truncated because Direct I/O + *write introduces some extra data for alignment. + */ + if (-1==file_truncate(file->fd, (file_offset_t)file->eof)) + HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} +#endif /* H5_HAVE_DIRECT */ diff --git a/src/H5FDdirect.h b/src/H5FDdirect.h new file mode 100644 index 0000000..25ff3de --- /dev/null +++ b/src/H5FDdirect.h @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Purpose: The public header file for the direct driver. + */ +#ifndef H5FDdirect_H +#define H5FDdirect_H + +#include "H5Ipublic.h" + +#ifdef H5_HAVE_DIRECT +# define H5FD_DIRECT (H5FD_direct_init()) +#else +# define H5FD_DIRECT (-1) +#endif /* H5_HAVE_DIRECT */ + +#ifdef H5_HAVE_DIRECT +#ifdef __cplusplus +extern "C" { +#endif + +H5_DLL hid_t H5FD_direct_init(void); +H5_DLL void H5FD_direct_term(void); +H5_DLL herr_t H5Pset_fapl_direct(hid_t fapl_id); + +#ifdef __cplusplus +} +#endif + +#endif /* H5_HAVE_DIRECT */ + +#endif diff --git a/src/H5FLprivate.h b/src/H5FLprivate.h index 8297fe9..1a4f065 100644 --- a/src/H5FLprivate.h +++ b/src/H5FLprivate.h @@ -35,7 +35,7 @@ /* Private headers needed by this file */ /* Macros for turning off free lists in the library */ -/* #define H5_NO_FREE_LISTS */ +/*#define H5_NO_FREE_LISTS*/ #if defined H5_NO_FREE_LISTS || defined H5_USING_PURIFY #define H5_NO_REG_FREE_LISTS #define H5_NO_ARR_FREE_LISTS diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index c0659d3..168a156 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -445,7 +445,7 @@ typedef struct H5F_t H5F_t; #define H5F_ACS_FAMILY_NEWSIZE_SIZE sizeof(hsize_t) #define H5F_ACS_FAMILY_NEWSIZE_DEF 0 -/* Definition for whether to conver family to sec2 driver. It's private +/* Definition for whether to convert family to sec2 driver. It's private * property only used by h5repart */ #define H5F_ACS_FAMILY_TO_SEC2_NAME "family_to_sec2" #define H5F_ACS_FAMILY_TO_SEC2_SIZE sizeof(hbool_t) diff --git a/src/H5Lexternal.c b/src/H5Lexternal.c index 878abfc..4ca5c83 100644 --- a/src/H5Lexternal.c +++ b/src/H5Lexternal.c @@ -138,9 +138,9 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group, if(H5Fclose(fid) < 0) goto error; - /* Open the external file */ if((fid = H5Fopen(file_name, intent, fapl_id)) < 0) goto error; + ret_value = H5Oopen(fid, obj_name, lapl_id); /* If this fails, our return value will be negative. */ if(H5Pclose(fapl_id) < 0) goto error; diff --git a/src/H5config.h.in b/src/H5config.h.in index 756553d..0853964 100644 --- a/src/H5config.h.in +++ b/src/H5config.h.in @@ -54,6 +54,9 @@ /* Define to 1 if you have the `difftime' function. */ #undef HAVE_DIFFTIME +/* Define if the direct I/O virtual file driver should be compiled */ +#undef HAVE_DIRECT + /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H diff --git a/src/Makefile.am b/src/Makefile.am index 3076db5..d37c4bc 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,7 +47,7 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5Defl.c H5Dio.c H5Distore.c H5Dmpio.c H5Doh.c H5Dselect.c H5Dtest.c \ H5E.c H5F.c \ H5Fdbg.c H5Ffake.c H5Fmount.c H5Fsfile.c H5Fsuper.c H5FD.c H5FDcore.c \ - H5FDfamily.c H5FDlog.c H5FDmpi.c H5FDmpio.c \ + H5FDdirect.c H5FDfamily.c H5FDlog.c H5FDmpi.c H5FDmpio.c \ H5FDmpiposix.c H5FDmulti.c H5FDsec2.c H5FDstdio.c \ H5FDstream.c H5FL.c H5FO.c H5FS.c H5FScache.c H5FSdbg.c H5FSsection.c \ H5G.c H5Gbtree2.c H5Gdense.c H5Gdeprec.c H5Gent.c H5Glink.c H5Gloc.c \ @@ -76,8 +76,8 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ # Public headers include_HEADERS =H5public.h H5Apublic.h H5ACpublic.h \ H5Cpublic.h H5Dpublic.h \ - H5Epubgen.h H5Epublic.h H5Fpublic.h H5FDpublic.h H5FDcore.h H5FDfamily.h \ - H5FDlog.h H5FDmpi.h H5FDmpio.h H5FDmpiposix.h \ + H5Epubgen.h H5Epublic.h H5Fpublic.h H5FDpublic.h H5FDcore.h H5FDdirect.h \ + H5FDfamily.h H5FDlog.h H5FDmpi.h H5FDmpio.h H5FDmpiposix.h \ H5FDmulti.h H5FDsec2.h H5FDstdio.h H5FDstream.h \ H5Gpublic.h H5Ipublic.h H5Lpublic.h \ H5MMpublic.h H5Opublic.h H5Ppublic.h H5Rpublic.h H5Spublic.h \ diff --git a/src/Makefile.in b/src/Makefile.in index 3a4c51b..728290e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -89,7 +89,7 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \ H5Defl.lo H5Dio.lo H5Distore.lo H5Dmpio.lo H5Doh.lo \ H5Dselect.lo H5Dtest.lo H5E.lo H5F.lo H5Fdbg.lo H5Ffake.lo \ H5Fmount.lo H5Fsfile.lo H5Fsuper.lo H5FD.lo H5FDcore.lo \ - H5FDfamily.lo H5FDlog.lo H5FDmpi.lo H5FDmpio.lo \ + H5FDdirect.lo H5FDfamily.lo H5FDlog.lo H5FDmpi.lo H5FDmpio.lo \ H5FDmpiposix.lo H5FDmulti.lo H5FDsec2.lo H5FDstdio.lo \ H5FDstream.lo H5FL.lo H5FO.lo H5FS.lo H5FScache.lo H5FSdbg.lo \ H5FSsection.lo H5G.lo H5Gbtree2.lo H5Gdense.lo H5Gdeprec.lo \ @@ -398,7 +398,7 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ H5Defl.c H5Dio.c H5Distore.c H5Dmpio.c H5Doh.c H5Dselect.c H5Dtest.c \ H5E.c H5F.c \ H5Fdbg.c H5Ffake.c H5Fmount.c H5Fsfile.c H5Fsuper.c H5FD.c H5FDcore.c \ - H5FDfamily.c H5FDlog.c H5FDmpi.c H5FDmpio.c \ + H5FDdirect.c H5FDfamily.c H5FDlog.c H5FDmpi.c H5FDmpio.c \ H5FDmpiposix.c H5FDmulti.c H5FDsec2.c H5FDstdio.c \ H5FDstream.c H5FL.c H5FO.c H5FS.c H5FScache.c H5FSdbg.c H5FSsection.c \ H5G.c H5Gbtree2.c H5Gdense.c H5Gdeprec.c H5Gent.c H5Glink.c H5Gloc.c \ @@ -427,8 +427,8 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \ # Public headers include_HEADERS = H5public.h H5Apublic.h H5ACpublic.h \ H5Cpublic.h H5Dpublic.h \ - H5Epubgen.h H5Epublic.h H5Fpublic.h H5FDpublic.h H5FDcore.h H5FDfamily.h \ - H5FDlog.h H5FDmpi.h H5FDmpio.h H5FDmpiposix.h \ + H5Epubgen.h H5Epublic.h H5Fpublic.h H5FDpublic.h H5FDcore.h H5FDdirect.h \ + H5FDfamily.h H5FDlog.h H5FDmpi.h H5FDmpio.h H5FDmpiposix.h \ H5FDmulti.h H5FDsec2.h H5FDstdio.h H5FDstream.h \ H5Gpublic.h H5Ipublic.h H5Lpublic.h \ H5MMpublic.h H5Opublic.h H5Ppublic.h H5Rpublic.h H5Spublic.h \ @@ -581,6 +581,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5F.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FD.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDcore.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDdirect.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDfamily.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDlog.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5FDmpi.Plo@am__quote@ diff --git a/src/hdf5.h b/src/hdf5.h index cf3d762..a3ae138 100644 --- a/src/hdf5.h +++ b/src/hdf5.h @@ -47,5 +47,6 @@ #include "H5FDsec2.h" /* POSIX unbuffered file I/O */ #include "H5FDstdio.h" /* Standard C buffered I/O */ #include "H5FDstream.h" /* In-memory files streamed via sockets */ +#include "H5FDdirect.h" /* Linux direct I/O */ #endif diff --git a/test/h5test.c b/test/h5test.c index acc7630..5ca5d13 100644 --- a/test/h5test.c +++ b/test/h5test.c @@ -577,6 +577,11 @@ h5_fileaccess(void) if (H5Pset_fapl_log(fapl, NULL, log_flags, (size_t)0) < 0) return -1; + } else if (!HDstrcmp(name, "direct")) { +#ifdef H5_HAVE_DIRECT + /* Linux direct read() and write() system calls */ + if (H5Pset_fapl_direct(fapl)<0) return -1; +#endif } else { /* Unknown driver */ return -1; diff --git a/test/reserved.c b/test/reserved.c index 769cfb5..8033618 100755 --- a/test/reserved.c +++ b/test/reserved.c @@ -54,6 +54,7 @@ rsrv_heap(void) /* Create a new file. */ fapl = h5_fileaccess(); + h5_fixname(FILENAME[0], fapl, filename, sizeof filename); /* Set file address sizes to be very small. */ fcpl = H5Pcreate(H5P_FILE_CREATE); diff --git a/test/vfd.c b/test/vfd.c index a67f18f..952ed4d 100644 --- a/test/vfd.c +++ b/test/vfd.c @@ -33,6 +33,7 @@ const char *FILENAME[] = { "core_file", "family_file", "multi_file", + "direct_file", NULL }; @@ -118,6 +119,88 @@ error: /*------------------------------------------------------------------------- + * Function: test_direct + * + * Purpose: Tests the file handle interface for DIRECT I/O driver + * + * Return: Success: exit(0) + * + * Failure: exit(1) + * + * Programmer: Raymond Lu + * Wednesday, 20 September 2006 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +test_direct(void) +{ +#ifdef H5_HAVE_DIRECT + hid_t file=(-1), fapl, access_fapl = -1; + char filename[1024]; + int *fhandle=NULL; + hsize_t file_size; +#endif /*H5_HAVE_DIRECT*/ + + TESTING("Direct I/O file driver"); + +#ifndef H5_HAVE_DIRECT + SKIPPED(); + return 0; +#else /*H5_HAVE_DIRECT*/ + + /* Set property list and file name for SEC2 driver. */ + fapl = h5_fileaccess(); + if(H5Pset_fapl_direct(fapl)<0) + TEST_ERROR; + h5_fixname(FILENAME[4], fapl, filename, sizeof filename); + + if((file=H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl))<0) + TEST_ERROR; + + /* Retrieve the access property list... */ + if ((access_fapl = H5Fget_access_plist(file)) < 0) + TEST_ERROR; + + /* ...and close the property list */ + if (H5Pclose(access_fapl) < 0) + TEST_ERROR; + + /* Check file handle API */ + if(H5Fget_vfd_handle(file, H5P_DEFAULT, (void **)&fhandle)<0) + TEST_ERROR; + if(*fhandle<0) + TEST_ERROR; + + /* Check file size API */ + if(H5Fget_filesize(file, &file_size) < 0) + TEST_ERROR; + + /* There is no garantee the size of metadata in file is constant. + * Just try to check if it's reasonable. It's 2KB right now. + */ + if(file_size<1*KB || file_size>4*KB) + TEST_ERROR; + + if(H5Fclose(file)<0) + TEST_ERROR; + h5_cleanup(FILENAME, fapl); + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY { + H5Pclose (fapl); + H5Fclose(file); + } H5E_END_TRY; + return -1; +#endif /*H5_HAVE_DIRECT*/ +} + + +/*------------------------------------------------------------------------- * Function: test_core * * Purpose: Tests the file handle interface for CORE driver @@ -736,6 +819,7 @@ main(void) nerrors += test_family()<0 ?1:0; nerrors += test_family_compat()<0 ?1:0; nerrors += test_multi()<0 ?1:0; + nerrors += test_direct()<0 ?1:0; if (nerrors){ printf("***** %d Virtual File Driver TEST%s FAILED! *****\n", diff --git a/tools/h5dump/h5dump.c b/tools/h5dump/h5dump.c index fdee5d1..1ec69aa 100644 --- a/tools/h5dump/h5dump.c +++ b/tools/h5dump/h5dump.c @@ -638,7 +638,7 @@ usage(const char *prog) fprintf(stdout, " -k L, --block=L Size of block in hyperslab\n"); fprintf(stdout, "\n"); fprintf(stdout, " D - is the file driver to use in opening the file. Acceptable values\n"); - fprintf(stdout, " are \"sec2\", \"family\", \"split\", \"multi\", and \"stream\". Without\n"); + fprintf(stdout, " are \"sec2\", \"family\", \"split\", \"multi\", \"direct\", and \"stream\". Without\n"); fprintf(stdout, " the file driver flag, the file will be opened with each driver in\n"); fprintf(stdout, " turn and in the order specified above until one driver succeeds\n"); fprintf(stdout, " in opening the file.\n"); @@ -2691,7 +2691,7 @@ dump_fcpl(hid_t fid) unsigned stab; /* symbol table entry version # */ unsigned shhdr; /* shared object header version # */ hid_t fdriver; /* file driver */ - char dname[15]; /* buffer to store driver name */ + char dname[32]; /* buffer to store driver name */ unsigned sym_lk; /* symbol table B-tree leaf 'K' value */ unsigned sym_ik; /* symbol table B-tree internal 'K' value */ unsigned istore_ik; /* indexed storage B-tree internal 'K' value */ @@ -2731,6 +2731,8 @@ dump_fcpl(hid_t fid) if (H5FD_CORE==fdriver) HDstrcpy(dname,"H5FD_CORE"); + else if (H5FD_DIRECT==fdriver) + HDstrcpy(dname,"H5FD_DIRECT"); else if (H5FD_FAMILY==fdriver) HDstrcpy(dname,"H5FD_FAMILY"); else if (H5FD_LOG==fdriver) @@ -2747,7 +2749,9 @@ dump_fcpl(hid_t fid) else if (H5FD_STREAM==fdriver) HDstrcpy(dname,"H5FD_STREAM"); #endif - + else + HDstrcpy(dname,"Unknown driver"); + indentation(indent + COL); printf("%s %s\n","FILE_DRIVER", dname); indentation(indent + COL); @@ -6239,6 +6243,10 @@ h5_fileaccess(void) if (H5Pset_fapl_log(fapl, NULL, (unsigned)log_flags, 0) < 0) return -1; + } else if (!HDstrcmp(name, "direct")) { + /* Substitute Direct I/O driver with sec2 driver temporarily because + * some output has sec2 driver as the standard. */ + if (H5Pset_fapl_sec2(fapl)<0) return -1; } else { /* Unknown driver */ return -1; -- cgit v0.12