summaryrefslogtreecommitdiffstats
path: root/src/H5Fmpio.c
diff options
context:
space:
mode:
authorRobert Kim Yates <rkyates@llnl.gov>1998-02-02 16:26:49 (GMT)
committerRobert Kim Yates <rkyates@llnl.gov>1998-02-02 16:26:49 (GMT)
commita6f59faa9deea96ed2a8500ea53f5ef0f0a565ce (patch)
treef46ba7832c2c9acc9e812522329f2328c410b5e0 /src/H5Fmpio.c
parent8831ff175c42845c6c523fbbbf035ec1f00a779c (diff)
downloadhdf5-a6f59faa9deea96ed2a8500ea53f5ef0f0a565ce.zip
hdf5-a6f59faa9deea96ed2a8500ea53f5ef0f0a565ce.tar.gz
hdf5-a6f59faa9deea96ed2a8500ea53f5ef0f0a565ce.tar.bz2
[svn-r211] Added hooks for MPI-IO low-level I/O module.
Diffstat (limited to 'src/H5Fmpio.c')
-rw-r--r--src/H5Fmpio.c549
1 files changed, 549 insertions, 0 deletions
diff --git a/src/H5Fmpio.c b/src/H5Fmpio.c
new file mode 100644
index 0000000..b82e709
--- /dev/null
+++ b/src/H5Fmpio.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 1998 NCSA
+ * All rights reserved.
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ * Purpose: This is the MPI2 I/O subclass of H5Flow.
+ *
+ * Problems and limitations:
+ *
+ * H5F_mpio_access
+ * - Since there is no "access" function for MPI-IO files
+ * we open (i.e., MPI_File_open) the file to see if it exists
+ * and to infer the access flags. If the file is opened,
+ * we close it without reading or writing it.
+ * - It is not possible within MPI-IO to determine whether or not
+ * the names "file1" and "file2" refer to the same physical fileC
+ * (at least not without writing one and reading the other).
+ * So we do what H5F_core_open() does: return a bogus device
+ * number and a unique inode number.
+ * This has the side effect that calling H5Fopen() twice
+ * with the same name really does open the file twice
+ * and the two handles don't communicate with each other,
+ * resulting in trashing the file. It also runs the (very small)
+ * risk of having two unrelated names be seen as the same file.
+ *
+ * H5F_mpio_open
+ * - should take MPI communicator and MPI info as parameters
+ * (currently uses MPI_COMM_WORLD and MPI_INFO_NULL)
+ * - "unique" key treated same as in H5F_mpio_access
+ *
+ * H5F_mpio_read
+ * - always does independent read (not collective)
+ *
+ * H5F_MPIOff_to_haddr and H5F_haddr_to_MPIOff
+ * - For now, we assume that MPI_Offset and haddr_t
+ * are the same size. Needs to be generalized.
+ */
+#include <mpi.h>
+#include <mpio.h>
+#include <H5private.h>
+#include <H5private.h>
+#include <H5Eprivate.h>
+#include <H5Fprivate.h>
+#include <H5MMprivate.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define PABLO_MASK H5F_mpio
+static hbool_t interface_initialize_g = FALSE; /* rky??? */
+#define INTERFACE_INIT NULL
+
+#define H5F_MPIO_DEV 0xfffe /*pseudo dev for MPI-IO until we fix things */
+ /* Make sure this differs from H5F_CORE_DEV */
+
+static hbool_t H5F_mpio_access(const char *name, int mode,
+ H5F_search_t *key /*out */ );
+static H5F_low_t *H5F_mpio_open(const char *name, uintn flags,
+ H5F_search_t *key);
+static herr_t H5F_mpio_close(H5F_low_t *lf);
+static herr_t H5F_mpio_read(H5F_low_t *lf, const haddr_t *addr,
+ size_t size, uint8 *buf);
+static herr_t H5F_mpio_write(H5F_low_t *lf, const haddr_t *addr,
+ size_t size, const uint8 *buf);
+static herr_t H5F_mpio_flush(H5F_low_t *lf);
+static haddr_t H5F_MPIOff_to_haddr( MPI_Offset mpi_off );
+static MPI_Offset H5F_haddr_to_MPIOff( haddr_t addr );
+
+const H5F_low_class_t H5F_LOW_MPIO[1] =
+{
+ {
+ H5F_mpio_access, /* access method */
+ H5F_mpio_open, /* open method */
+ H5F_mpio_close, /* close method */
+ H5F_mpio_read, /* read method */
+ H5F_mpio_write, /* write method */
+ H5F_mpio_flush, /* flush method */
+ NULL /* extend method */
+ }};
+
+ino_t mpio_inode_num = 0; /* fake "inode" number */
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpio_access
+ *
+ * Purpose: Determines if an MPI-IO file can be accessed in a particular
+ * way. The access modes for a file are the same as those of
+ * access(2), namely
+ *
+ * F_OK: determines if the MPI-IO file exists
+ * (in fact, we can only determine that the file can be
+ * opened for reading or writing, or neither)
+ *
+ * R_OK: determines if the MPI-IO file is readable
+ *
+ * W_OK: determines if the MPI-IO file is writable.
+ *
+ * Warning: It is not possible within MPI-IO to determine whether or not
+ * the names "file1" and "file2" refer to the same physical fileC
+ * (at least not without writing one and reading the other).
+ * So we do what H5F_core_open() does: return a bogus device number
+ * and a unique inode number.
+ * This has the side effect that calling H5Fopen() twice
+ * with the same name really does open the file twice
+ * and the two handles don't communicate with each other,
+ * resulting in trashing the file. It also runs the (very small)
+ * risk of having two unrelated names be seen as the same file.
+ *
+ * Return: Success: TRUE or FALSE. If TRUE, then KEY is
+ * initialized with data that makes this file
+ * unique (same value as H5F_low_open).
+ *
+ * Failure: FAIL, KEY is undefined.
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hbool_t
+H5F_mpio_access(char *name, int mode, H5F_search_t *key /*out */ )
+{
+ hbool_t ret_val = FALSE;
+ MPI_File fh;
+ int mpierr;
+ int mpi_mode;
+
+ FUNC_ENTER(H5F_mpio_access, FAIL);
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Entering H5F_mpio_access name=%s mode=%x\n", name, mode );
+#endif
+
+ /* The only way to get this info in MPI-IO is to try to open the file */
+ /* (though particular implementations of MPI-IO may allow other ways) */
+
+ switch (mode) {
+ case F_OK: mpi_mode = MPI_MODE_RDONLY;
+ /* to see if it exists, first try to open for read */
+ break;
+ case R_OK: mpi_mode = MPI_MODE_RDONLY;
+ break;
+ case W_OK: mpi_mode = MPI_MODE_WRONLY;
+ break;
+ default: HRETURN_ERROR(H5E_IO, H5E_ARGS, FAIL,
+ "invalid mode parameter");
+ }
+
+ mpierr = MPI_File_open( MPI_COMM_SELF, name, mpi_mode, MPI_INFO_NULL, &fh );
+ if (mpierr == MPI_SUCCESS) {
+ mpierr = MPI_File_close( &fh );
+ if (mpierr != MPI_SUCCESS)
+ HRETURN_ERROR(H5E_IO, H5E_ARGS, FAIL, "MPI_File_close failed");
+ ret_val = TRUE;
+ } else if (mode == F_OK) {
+ /* to see if it exists, this time try to open for write */
+ mpierr = MPI_File_open( MPI_COMM_SELF, name, MPI_MODE_WRONLY,
+ MPI_INFO_NULL, &fh );
+ if (mpierr == MPI_SUCCESS) {
+ mpierr = MPI_File_close( &fh );
+ if (mpierr != MPI_SUCCESS)
+ HRETURN_ERROR(H5E_IO, H5E_INTERNAL, FAIL, "MPI_File_close failed");
+ ret_val = TRUE;
+ }
+ }
+
+ /* if the file exists, provide its (not really) unique key */
+ if ((ret_val==TRUE) && key) {
+ key->dev = H5F_MPIO_DEV;
+ key->ino = mpio_inode_num++;
+ }
+
+#ifdef DEBUG_MPIO
+ if (key)
+ fprintf(stdout,
+ "Leaving H5F_mpio_access ret_val=%d key->dev=%x key->ino=%d\n",
+ ret_val, key->dev, key->ino );
+ else
+ fprintf(stdout,
+ "Leaving H5F_mpio_access ret_val=%d\n", ret_val );
+#endif
+
+ FUNC_LEAVE(ret_val);
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpio_open
+ *
+ * Purpose: Opens a file with name NAME. The FLAGS are a bit field with
+ * the possible values defined in H5F_low_open().
+ *
+ * Errors:
+ * IO CANTOPENFILE MPI_File_open failed.
+ * IO CANTOPENFILE MPI_File_get_size failed.
+ * IO CANTOPENFILE MPI_File_set_size failed (for truncate).
+ *
+ * Return: Success: Low-level file pointer
+ *
+ * Failure: NULL
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5F_low_t *
+H5F_mpio_open(char *name, uintn flags, H5F_search_t *key /*out */ )
+{
+ H5F_low_t *lf = NULL;
+ MPI_File fh;
+ int mpi_amode;
+ char mpierrmsg[MPI_MAX_ERROR_STRING];
+ int mpierr, msglen, myid;
+ MPI_Offset size;
+
+ FUNC_ENTER(H5F_mpio_open, NULL);
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Entering H5F_mpio_open name=%s flags=%x\n", name, flags );
+#endif
+
+ /* convert HDF5 flags to MPI-IO flags */
+ /* some combinations are illegal; let MPI-IO figure it out */
+ mpi_amode = (flags&H5F_ACC_WRITE) ? MPI_MODE_RDWR : MPI_MODE_RDONLY;
+ if (flags&H5F_ACC_CREAT) mpi_amode |= MPI_MODE_CREATE;
+ if (flags&H5F_ACC_EXCL) mpi_amode |= MPI_MODE_EXCL;
+
+ mpierr = MPI_File_open(MPI_COMM_WORLD, name, mpi_amode, MPI_INFO_NULL, &fh);
+ if (mpierr != MPI_SUCCESS) {
+ MPI_Error_string( mpierr, mpierrmsg, &msglen );
+ HRETURN_ERROR(H5E_IO, H5E_CANTOPENFILE, NULL, mpierrmsg );
+ }
+
+ /* proc 0 truncates the file, if requested */
+ MPI_Comm_rank( MPI_COMM_WORLD, &myid );
+ if ((myid==0) && (flags&H5F_ACC_TRUNC)) {
+ mpierr = MPI_File_set_size( fh, (MPI_Offset)0 );
+ }
+ MPI_Barrier( MPI_COMM_WORLD );
+
+ /* Build the return value */
+ lf = H5MM_xcalloc(1, sizeof(H5F_low_t));
+ lf->u.mpio.f = fh;
+ H5F_addr_reset(&(lf->eof));
+ mpierr = MPI_File_get_size( fh, &size );
+ if (mpierr != MPI_SUCCESS) {
+ MPI_File_close( &(lf->u.mpio.f) );
+ MPI_Error_string( mpierr, mpierrmsg, &msglen );
+ HRETURN_ERROR(H5E_IO, H5E_CANTOPENFILE, NULL, mpierrmsg );
+ } else {
+ haddr_t new_eof = H5F_MPIOff_to_haddr( size );
+ H5F_low_seteof( lf, &new_eof );
+ }
+
+ /* The unique key */
+ if (key) {
+ key->dev = H5F_MPIO_DEV;
+ key->ino = mpio_inode_num++;
+ }
+
+#ifdef DEBUG_MPIO
+ if (key)
+ fprintf(stdout,
+ "Leaving H5F_mpio_open key->dev=%x key->ino=%d\n",
+ key->dev, key->ino );
+ else
+ fprintf(stdout,
+ "Leaving H5F_mpio_open\n" );
+#endif
+
+ FUNC_LEAVE(lf);
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpio_close
+ *
+ * Purpose: Closes a file.
+ *
+ * Errors:
+ * IO CLOSEERROR Fclose failed.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_mpio_close(H5F_low_t *lf)
+{
+ int mpierr;
+ char mpierrmsg[MPI_MAX_ERROR_STRING];
+ int msglen;
+
+ FUNC_ENTER(H5F_mpio_close, FAIL);
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Entering H5F_mpio_close\n" );
+#endif
+
+ mpierr = MPI_File_close( &(lf->u.mpio.f) );
+ /* MPI_File_close sets lf->u.mpio.f to MPI_FILE_NULL */
+
+ if (mpierr != MPI_SUCCESS) {
+ MPI_Error_string( mpierr, mpierrmsg, &msglen );
+ HRETURN_ERROR(H5E_IO, H5E_CLOSEERROR, FAIL, mpierrmsg );
+ }
+
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Leaving H5F_mpio_close\n" );
+#endif
+ FUNC_LEAVE(SUCCEED);
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpio_read
+ *
+ * Purpose: Reads SIZE bytes beginning at address ADDR in file LF and
+ * places them in buffer BUF. Reading past the logical or
+ * physical end of file returns zeros instead of failing.
+ *
+ * Errors:
+ * IO READERROR MPI_File_read_at failed.
+ * IO READERROR MPI_Get_count failed
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_mpio_read(H5F_low_t *lf, const haddr_t *addr, size_t size, uint8 *buf)
+{
+ MPI_Offset mpi_off, bytes_read;
+ MPI_Status mpi_stat;
+ int mpierr;
+ char mpierrmsg[MPI_MAX_ERROR_STRING];
+ int msglen;
+ size_t n, br;
+
+ FUNC_ENTER(H5F_mpio_read, FAIL);
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Entering H5F_mpio_read\n" );
+#endif
+
+ /* Check empty read */
+ if (0 == size)
+ HRETURN(SUCCEED);
+
+ /* Read the data. */
+ mpi_off = H5F_haddr_to_MPIOff( *addr );
+ fprintf(stdout, "In H5F_mpio_read, before calling MPI_File_read_at\n" );
+ mpierr = MPI_File_read_at( lf->u.mpio.f, mpi_off, (void*) buf,
+ (int) size, MPI_BYTE, &mpi_stat );
+ fprintf(stdout, "In H5F_mpio_read, after calling MPI_File_read_at\n" );
+ if (mpierr != MPI_SUCCESS) {
+ MPI_Error_string( mpierr, mpierrmsg, &msglen );
+ HRETURN_ERROR(H5E_IO, H5E_READERROR, FAIL, mpierrmsg );
+ }
+
+ /* How many bytes were actually read? */
+ mpierr = MPI_Get_count( &mpi_stat, MPI_BYTE, &bytes_read );
+ if (mpierr != MPI_SUCCESS) {
+ MPI_Error_string( mpierr, mpierrmsg, &msglen );
+ HRETURN_ERROR(H5E_IO, H5E_READERROR, FAIL, mpierrmsg );
+ }
+
+ /* read zeroes past the end of the file */
+ br = (size_t)bytes_read;
+ if ((n=(size-br)) > 0)
+ HDmemset( buf+br, 0, n);
+
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Leaving H5F_mpio_read\n" );
+#endif
+ FUNC_LEAVE(SUCCEED);
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpio_write
+ *
+ * Purpose: Writes SIZE bytes from the beginning of BUF into file LF at
+ * file address ADDR.
+ *
+ * Errors:
+ * IO WRITEERROR MPI_File_write_at failed.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_mpio_write(H5F_low_t *lf, const haddr_t *addr, size_t size,
+ const uint8 *buf)
+{
+ MPI_Offset mpi_off;
+ MPI_Status mpi_stat;
+ int mpierr;
+ char mpierrmsg[MPI_MAX_ERROR_STRING];
+ int msglen;
+
+ FUNC_ENTER(H5F_mpio_write, FAIL);
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Entering H5F_mpio_write\n" );
+#endif
+
+ /* Check empty write */
+ if (0 == size)
+ HRETURN(SUCCEED);
+
+ /* Write the data. */
+ mpi_off = H5F_haddr_to_MPIOff( *addr );
+ mpierr = MPI_File_write_at( lf->u.mpio.f, mpi_off, (void*) buf,
+ (int) size, MPI_BYTE, &mpi_stat );
+ if (mpierr != MPI_SUCCESS) {
+ MPI_Error_string( mpierr, mpierrmsg, &msglen );
+ HRETURN_ERROR(H5E_IO, H5E_READERROR, FAIL, mpierrmsg );
+ }
+
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Leaving H5F_mpio_write\n" );
+#endif
+ FUNC_LEAVE(SUCCEED);
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_mpio_flush
+ *
+ * Purpose: Makes sure that all data is on disk.
+ *
+ * Errors:
+ * IO WRITEERROR Fflush failed.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5F_mpio_flush(H5F_low_t *lf)
+{
+ int mpierr;
+ char mpierrmsg[MPI_MAX_ERROR_STRING];
+ int msglen;
+
+ FUNC_ENTER(H5F_mpio_flush, FAIL);
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Entering H5F_mpio_flush\n" );
+#endif
+
+ mpierr = MPI_File_sync( lf->u.mpio.f );
+ if (mpierr != MPI_SUCCESS) {
+ MPI_Error_string( mpierr, mpierrmsg, &msglen );
+ HRETURN_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, mpierrmsg );
+ }
+#ifdef DEBUG_MPIO
+ fprintf(stdout, "Leaving H5F_mpio_flush\n" );
+#endif
+ FUNC_LEAVE(SUCCEED);
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_MPIOff_to_haddr(size) );
+ *
+ * Purpose: Convert an MPI_Offset value to haddr_t.
+ *
+ * Problems and limitations:
+ * For now, we assume that MPI_Offset and haddr_t
+ * are the same size. Needs to be generalized.
+ *
+ * Return: Success: the offset value, as an hddr_t.
+ *
+ * Failure: 0
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5F_MPIOff_to_haddr( MPI_Offset mpi_off )
+{
+ haddr_t addr;
+
+ addr.offset = (uint64) mpi_off;
+
+ return(addr);
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5F_haddr_to_MPIOff(size) );
+ *
+ * Purpose: Convert an haddr_t value to MPI_Offset.
+ *
+ * Problems and limitations:
+ * For now, we assume that MPI_Offset and haddr_t
+ * are the same size. Needs to be generalized.
+ *
+ * Return: Success: the offset value, as an MPI_Offset.
+ *
+ * Failure: 0
+ *
+ * Programmer:
+ * January 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static MPI_Offset
+H5F_haddr_to_MPIOff( haddr_t addr )
+{
+ MPI_Offset mpi_off;
+
+ FUNC_ENTER(H5F_haddr_to_MPIOff, (MPI_Offset)0);
+
+ mpi_off = (MPI_Offset) addr.offset;
+
+ FUNC_LEAVE(mpi_off);
+}