summaryrefslogtreecommitdiffstats
path: root/src/H5FDmulti.c
diff options
context:
space:
mode:
authorRobb Matzke <matzke@llnl.gov>1999-08-17 19:12:59 (GMT)
committerRobb Matzke <matzke@llnl.gov>1999-08-17 19:12:59 (GMT)
commitcc89b8a605dfc7370cb760e6c3d7339cbf1e9884 (patch)
tree82e0552ea6a80a2e362fdc77960a3483648aae75 /src/H5FDmulti.c
parent5ef0237e2fe5ac6aee0d97fdc6bcf22f72d47162 (diff)
downloadhdf5-cc89b8a605dfc7370cb760e6c3d7339cbf1e9884.zip
hdf5-cc89b8a605dfc7370cb760e6c3d7339cbf1e9884.tar.gz
hdf5-cc89b8a605dfc7370cb760e6c3d7339cbf1e9884.tar.bz2
[svn-r1572] Changes since 19990810
---------------------- ./MANIFEST ./src/H5FDmulti.c [NEW] ./src/H5FDmulti.h [NEW] ./src/Makefile.in ./src/hdf5.h The split driver was reimplemented as a more general "multi" driver which is capable of splitting data into multiple files like the family driver except the partioning is done by memory usage type instead of address. The H5Pset_fapl_split() function just calls H5Pset_fapl_multi() with arguments which prepare to split the address space into two files: meta and raw data. This is the first version. I plan to allow the open() call to relax a bit which would allow one to open an hdf5 file when only the meta-data file is present. This would allow a very large file to be split and stored on tape and the relatively small meta file to be mirrored on disk to allow limited browsing of the file (any request for raw data would fail). ./src/H5private.h ./src/H5F.c ./src/H5FD.c ./src/H5FDprivate.h ./src/H5FDpublic.h ./src/H5FDcore.c ./src/H5FDfamily.c ./src/H5FDmpio.c ./src/H5FDsec2.c Added the ability for a file driver to store information in the superblock which would be needed if the file were opened again later for reading. The format is driver-defined which allows users to extend it however they like. ./doc/html/H5.format.html Added information about the new driver information block of the superblock. This is where file drivers store information they need in order to reopen the file later. ./src/H5F.c ./src/H5Fprivate.h ./src/H5FD.c ./src/H5FDprivate.h ./src/H5FDpublic.h ./src/H5FDcore.c ./src/H5FDfamily.c ./src/H5FDmpio.c ./src/H5FDsec2.c ./src/H5Fistore.c ./src/H5R.c The file access properties and the file access property list were decoupled, which allows the property list to more cleanly contain properties for various levels of the file and which allows the property list to be modified more cleanly when opening files. ./src/H5.c ./src/H5FDpublic.h Removed H5FD_MEM_META and H5FD_MEM_GROUP since they're never used. ./src/H5D.c Changed the way we detect the MPIO driver in all these special cases. ./src/H5F.c ./src/H5Rpublic.h ./test/tfile.c The default file sizeof(offset) was changed to be a function of haddr_t instead of hsize_t. THE H5RPUBLIC.H DEFINITIONS WILL HAVE PROBLEMS IF THE USER CREATES A FILE WITH NON-DEFAULT OFFSET AND SIZE SIZES! ./src/H5F.c Fixed an uninitialized memory access bug in file closing related to the VFL. ./src/H5T.c ./src/H5Tpublic.h Added an H5T_NATIVE_HADDR predefined datatype which corresponds to the `haddr_t' type. ./test/Makefile.in Reformatted long lines. ./test/big.c ./test/cmpd_dset.c ./test/dsets.c ./test/dtypes.c ./test/extend.c ./test/external.c Removed the H5F_ACC_DEBUG flag from file creation/open calls. ./test/big.c Plugged a memory leak. ./test/h5test.c Added support for the `multi' driver. Removed #warning about not having the stdio driver. Plans are to not implement it since the sec2 driver serves the same purpose and testing didn't show any difference in execution times between the two.
Diffstat (limited to 'src/H5FDmulti.c')
-rw-r--r--src/H5FDmulti.c1393
1 files changed, 1393 insertions, 0 deletions
diff --git a/src/H5FDmulti.c b/src/H5FDmulti.c
new file mode 100644
index 0000000..a8c9325
--- /dev/null
+++ b/src/H5FDmulti.c
@@ -0,0 +1,1393 @@
+/*
+ * Copyright (C) 1997 NCSA
+ * All rights reserved.
+ *
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, November 10, 1997
+ *
+ * Purpose: Implements a file driver which dispatches I/O requests to
+ * other file drivers depending on the purpose of the address
+ * region being accessed. For instance, all meta-data could be
+ * place in one file while all raw data goes to some other file.
+ */
+#include <assert.h>
+#include <hdf5.h>
+#include <stdlib.h>
+
+/*
+ * Define H5FD_MULTI_DEBUG if you want the ability to print debugging
+ * messages to the standard error stream. Messages are only printed if the
+ * file is opened with the H5F_ACC_DEBUG flag.
+ */
+#define H5FD_MULTI_DEBUG
+
+/* Our versions of MIN and MAX */
+#undef MAX
+#define MAX(X,Y) ((X)>(Y)?(X):(Y))
+#undef MIN
+#define MIN(X,Y) ((X)<(Y)?(X):(Y))
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_MULTI_g = 0;
+
+/*
+ * The description of a file belonging to this driver. The file access
+ * properties and member names do not have to be copied into this struct
+ * since they will be held open by the file access property list which is
+ * copied into the parent file struct in H5F_open().
+ */
+typedef struct H5FD_multi_t {
+ H5FD_t pub; /*public stuff, must be first */
+ H5FD_mem_t memb_map[H5FD_MEM_NTYPES]; /*map from usage to file */
+ haddr_t memb_addr[H5FD_MEM_NTYPES];/*starting address per member*/
+ haddr_t memb_next[H5FD_MEM_NTYPES];/*addr of next member */
+ H5FD_t *memb[H5FD_MEM_NTYPES]; /*member pointers */
+ hid_t memb_fapl[H5FD_MEM_NTYPES];/*member file access props */
+ char *memb_name[H5FD_MEM_NTYPES];/*name generators */
+ haddr_t eoa; /*end of allocated addresses */
+ unsigned flags; /*file open flags saved for debugging */
+} H5FD_multi_t;
+
+/* Driver-specific file access properties */
+typedef struct H5FD_multi_fapl_t {
+ H5FD_mem_t memb_map[H5FD_MEM_NTYPES]; /*memory usage map */
+ hid_t memb_fapl[H5FD_MEM_NTYPES];/*member access properties */
+ char *memb_name[H5FD_MEM_NTYPES];/*name generators */
+ haddr_t memb_addr[H5FD_MEM_NTYPES];/*starting addr per member */
+} H5FD_multi_fapl_t;
+
+/* Driver specific data transfer properties */
+typedef struct H5FD_multi_dxpl_t {
+ hid_t memb_dxpl[H5FD_MEM_NTYPES];/*member data xfer properties*/
+} H5FD_multi_dxpl_t;
+
+/* Private functions */
+static char *my_strdup(const char *s);
+
+/* Callback prototypes */
+static hsize_t H5FD_multi_sb_size(H5FD_t *file);
+static herr_t H5FD_multi_sb_encode(H5FD_t *file, char *name/*out*/,
+ unsigned char *buf/*out*/);
+static herr_t H5FD_multi_sb_decode(H5FD_t *file, const char *name,
+ const unsigned char *buf);
+static void *H5FD_multi_fapl_get(H5FD_t *file);
+static void *H5FD_multi_fapl_copy(const void *_old_fa);
+static herr_t H5FD_multi_fapl_free(void *_fa);
+static void *H5FD_multi_dxpl_copy(const void *_old_dx);
+static herr_t H5FD_multi_dxpl_free(void *_dx);
+static H5FD_t *H5FD_multi_open(const char *name, unsigned flags,
+ hid_t fapl_id, haddr_t maxaddr);
+static herr_t H5FD_multi_close(H5FD_t *_file);
+static int H5FD_multi_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static haddr_t H5FD_multi_get_eoa(H5FD_t *_file);
+static herr_t H5FD_multi_set_eoa(H5FD_t *_file, haddr_t eoa);
+static haddr_t H5FD_multi_get_eof(H5FD_t *_file);
+static haddr_t H5FD_multi_alloc(H5FD_t *_file, H5FD_mem_t type, hsize_t size);
+static herr_t H5FD_multi_free(H5FD_t *_file, H5FD_mem_t type, haddr_t addr,
+ hsize_t size);
+static herr_t H5FD_multi_read(H5FD_t *_file, hid_t dxpl_id, haddr_t addr,
+ hsize_t size, void *_buf/*out*/);
+static herr_t H5FD_multi_write(H5FD_t *_file, hid_t dxpl_id, haddr_t addr,
+ hsize_t size, const void *_buf);
+static herr_t H5FD_multi_flush(H5FD_t *_file);
+
+/* The class struct */
+static const H5FD_class_t H5FD_multi_g = {
+ "multi", /*name */
+ HADDR_MAX, /*maxaddr */
+ H5FD_multi_sb_size, /*sb_size */
+ H5FD_multi_sb_encode, /*sb_encode */
+ H5FD_multi_sb_decode, /*sb_decode */
+ sizeof(H5FD_multi_fapl_t), /*fapl_size */
+ H5FD_multi_fapl_get, /*fapl_get */
+ H5FD_multi_fapl_copy, /*fapl_copy */
+ H5FD_multi_fapl_free, /*fapl_free */
+ sizeof(H5FD_multi_dxpl_t), /*dxpl_size */
+ H5FD_multi_dxpl_copy, /*dxpl_copy */
+ H5FD_multi_dxpl_free, /*dxpl_free */
+ H5FD_multi_open, /*open */
+ H5FD_multi_close, /*close */
+ H5FD_multi_cmp, /*cmp */
+ H5FD_multi_alloc, /*alloc */
+ H5FD_multi_free, /*free */
+ H5FD_multi_get_eoa, /*get_eoa */
+ H5FD_multi_set_eoa, /*set_eoa */
+ H5FD_multi_get_eof, /*get_eof */
+ H5FD_multi_read, /*read */
+ H5FD_multi_write, /*write */
+ H5FD_multi_flush, /*flush */
+ H5FD_FLMAP_DEFAULT, /*fl_map */
+};
+
+
+/*-------------------------------------------------------------------------
+ * Function: my_strdup
+ *
+ * Purpose: Private version of strdup()
+ *
+ * Return: Success: Ptr to new copy of string
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 13, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static char *
+my_strdup(const char *s)
+{
+ char *x;
+ if (!s) return NULL;
+ if (NULL==(x=malloc(strlen(s)+1))) return NULL;
+ strcpy(x, s);
+ return x;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the multi driver.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_multi_init(void)
+{
+ if (!H5FD_MULTI_g) {
+ H5FD_MULTI_g = H5FDregister(&H5FD_multi_g);
+ }
+ return H5FD_MULTI_g;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_split
+ *
+ * Purpose: Compatability function. Makes the multi driver act like the
+ * old split driver which stored meta data in one file and raw
+ * data in another file.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 11, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_split(hid_t fapl, const char *meta_ext, hid_t meta_plist_id,
+ const char *raw_ext, hid_t raw_plist_id)
+{
+ H5FD_mem_t mt, memb_map[H5FD_MEM_NTYPES];
+ hid_t memb_fapl[H5FD_MEM_NTYPES];
+ const char *memb_name[H5FD_MEM_NTYPES];
+ char meta_name[1024], raw_name[1024];
+ haddr_t memb_addr[H5FD_MEM_NTYPES];
+
+ /*NO TRACE*/
+
+ /* Initialize */
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ memb_map[mt] = (H5FD_MEM_DRAW==mt?mt:H5FD_MEM_SUPER);
+ memb_fapl[mt] = -1;
+ memb_name[mt] = NULL;
+ memb_addr[mt] = HADDR_UNDEF;
+ }
+
+ /* The file access properties */
+ memb_fapl[H5FD_MEM_SUPER] = meta_plist_id;
+ memb_fapl[H5FD_MEM_DRAW] = raw_plist_id;
+
+ /* The names */
+ sprintf(meta_name, "%%s%s", meta_ext?meta_ext:".meta");
+ memb_name[H5FD_MEM_SUPER] = meta_name;
+ sprintf(raw_name, "%%s%s", raw_ext?raw_ext:".raw");
+ memb_name[H5FD_MEM_DRAW] = raw_name;
+
+ /* The sizes */
+ memb_addr[H5FD_MEM_SUPER] = 0;
+ memb_addr[H5FD_MEM_DRAW] = HADDR_MAX/2;
+
+ return H5Pset_fapl_multi(fapl, memb_map, memb_fapl, memb_name, memb_addr);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_multi
+ *
+ * Purpose: Sets the file access property list FAPL_ID to use the multi
+ * driver. The MEMB_MAP array maps memory usage types to other
+ * memory usage types and is the mechanism which allows the
+ * caller to specify how many files are created. The array
+ * contains H5FD_MEM_NTYPES entries which are either the value
+ * H5FD_MEM_DEFAULT or a memory usage type and the number of
+ * unique values determines the number of files which are
+ * opened. For each memory usage type which will be associated
+ * with a file the MEMB_FAPL array should have a property list
+ * and the MEMB_NAME array should be a name generator (a
+ * printf-style format with a %s which will be replaced with the
+ * name passed to H5FDopen(), usually from H5Fcreate() or
+ * H5Fopen()).
+ *
+ * Example: To set up a multi file access property list which partitions
+ * data into meta and raw files each being 1/2 of the address
+ * space one would say:
+ *
+ * H5FD_mem_t mt, memb_map[H5FD_MEM_NTYPES];
+ * hid_t memb_fapl[H5FD_MEM_NTYPES];
+ * const char *memb[H5FD_MEM_NTYPES];
+ * haddr_t memb_addr[H5FD_MEM_NTYPES];
+ *
+ * // The mapping...
+ * for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ * memb_map[mt] = H5FD_MEM_SUPER;
+ * }
+ * memb_map[H5FD_MEM_DRAW] = H5FD_MEM_DRAW;
+ *
+ * // Member information
+ * memb_fapl[H5FD_MEM_SUPER] = H5P_DEFAULT;
+ * memb_name[H5FD_MEM_SUPER] = "%s.meta";
+ * memb_addr[H5FD_MEM_SUPER] = 0;
+ *
+ * memb_fapl[H5FD_MEM_DRAW] = H5P_DEFAULT;
+ * memb_name[H5FD_MEM_DRAW] = "%s.raw";
+ * memb_addr[H5FD_MEM_DRAW] = HADDR_MAX/2;
+ *
+ * hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
+ * H5Pset_fapl_multi(fapl, memb_map, memb_fapl,
+ * memb_name, memb_addr);
+ *
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_multi(hid_t fapl_id, const H5FD_mem_t *memb_map,
+ const hid_t *memb_fapl, const char **memb_name,
+ const haddr_t *memb_addr)
+{
+ H5FD_multi_fapl_t fa;
+ H5FD_mem_t mt, mmt;
+
+ /*NO TRACE*/
+
+ /* Check arguments */
+ if (H5P_FILE_ACCESS!=H5Pget_class(fapl_id)) return -1;
+ if (!memb_map) return -1;
+ if (!memb_fapl) return -1;
+ if (!memb_name) return -1;
+ if (!memb_addr) return -1;
+
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ /* Map usage type */
+ mmt = memb_map[mt];
+ if (mmt<0 || mmt>=H5FD_MEM_NTYPES) return -1;
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+
+ /*
+ * All members of MEMB_FAPL must be either defaults or actual file
+ * access property lists.
+ */
+ if (H5P_DEFAULT!=memb_fapl[mmt] &&
+ H5P_FILE_ACCESS!=H5Pget_class(memb_fapl[mmt])) return -1;
+
+ /* All names must be defined */
+ if (!memb_name[mmt] || !memb_name[mmt][0]) return -1;
+ }
+
+ /*
+ * Initialize driver specific information. No need to copy it into the FA
+ * struct since all members will be copied by H5Pset_driver().
+ */
+ memcpy(fa.memb_map, memb_map, H5FD_MEM_NTYPES*sizeof(H5FD_mem_t));
+ memcpy(fa.memb_fapl, memb_fapl, H5FD_MEM_NTYPES*sizeof(hid_t));
+ memcpy(fa.memb_name, memb_name, H5FD_MEM_NTYPES*sizeof(char*));
+ memcpy(fa.memb_addr, memb_addr, H5FD_MEM_NTYPES*sizeof(haddr_t));
+ return H5Pset_driver(fapl_id, H5FD_MULTI, &fa);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fapl_multi
+ *
+ * Purpose: Returns information about the multi file access property
+ * list though the function arguments which are the same as for
+ * H5Pset_fapl_multi() above.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fapl_multi(hid_t fapl_id, H5FD_mem_t *memb_map/*out*/,
+ hid_t *memb_fapl/*out*/, char **memb_name/*out*/,
+ haddr_t *memb_addr/*out*/)
+{
+ H5FD_multi_fapl_t *fa;
+ H5FD_mem_t mt;
+
+ /*NO TRACE*/
+
+ if (H5P_FILE_ACCESS!=H5Pget_class(fapl_id)) return -1;
+ if (H5FD_MULTI!=H5Pget_driver(fapl_id)) return -1;
+ if (NULL==(fa=H5Pget_driver_info(fapl_id))) return -1;
+
+ if (memb_map) {
+ memcpy(memb_map, fa->memb_map, H5FD_MEM_NTYPES*sizeof(H5FD_mem_t));
+ }
+ if (memb_fapl) {
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (fa->memb_fapl[mt]>=0) {
+ memb_fapl[mt] = H5Pcopy(fa->memb_fapl[mt]);
+ } else {
+ memb_fapl[mt] = fa->memb_fapl[mt]; /*default or bad ID*/
+ }
+ }
+ }
+ if (memb_name) {
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (fa->memb_name[mt]) {
+ memb_name[mt] = malloc(strlen(fa->memb_name[mt])+1);
+ strcpy(memb_name[mt], fa->memb_name[mt]);
+ } else {
+ memb_name[mt] = NULL;
+ }
+ }
+ }
+ if (memb_addr) {
+ memcpy(memb_addr, fa->memb_addr, H5FD_MEM_NTYPES*sizeof(haddr_t));
+ }
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_dxpl_multi
+ *
+ * Purpose: Set the data transfer property list DXPL_ID to use the multi
+ * driver with the specified data transfer properties for each
+ * memory usage type MEMB_DXPL[] (after the usage map is
+ * applied).
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, August 10, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_dxpl_multi(hid_t dxpl_id, const hid_t *memb_dxpl)
+{
+ H5FD_multi_dxpl_t dx;
+ H5FD_mem_t mt;
+
+ /*NO TRACE*/
+
+ /* Check arguments */
+ if (H5P_DATA_XFER!=H5Pget_class(dxpl_id)) return -1;
+ if (!memb_dxpl) return -1;
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (H5P_DEFAULT!=memb_dxpl[mt] &&
+ H5P_DATA_XFER!=H5Pget_class(memb_dxpl[mt])) return -1;
+ }
+
+ /* Initialize the data transfer property list */
+ memcpy(dx.memb_dxpl, memb_dxpl, H5FD_MEM_NTYPES*sizeof(hid_t));
+ return H5Pset_driver(dxpl_id, H5FD_MULTI, &dx);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_dxpl_multi
+ *
+ * Purpose: Returns information which was set with H5Pset_dxpl_multi()
+ * above.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Tuesday, August 10, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_dxpl_multi(hid_t dxpl_id, hid_t *memb_dxpl/*out*/)
+{
+ H5FD_multi_dxpl_t *dx;
+ H5FD_mem_t mt;
+
+ /*NO TRACE*/
+
+ if (H5P_FILE_ACCESS!=H5Pget_class(dxpl_id)) return -1;
+ if (H5FD_MULTI!=H5Pget_driver(dxpl_id)) return -1;
+ if (NULL==(dx=H5Pget_driver_info(dxpl_id))) return -1;
+
+ if (memb_dxpl) {
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (dx->memb_dxpl[mt]>=0) {
+ memb_dxpl[mt] = H5Pcopy(dx->memb_dxpl[mt]);
+ } else {
+ memb_dxpl[mt] = dx->memb_dxpl[mt]; /*default or bad ID */
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_sb_size
+ *
+ * Purpose: Returns the size of the private information to be stored in
+ * the superblock.
+ *
+ * Return: Success: The super block driver data size.
+ *
+ * Failure: never fails
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 16, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5FD_multi_sb_size(H5FD_t *_file/*unused*/)
+{
+ return H5FD_MEM_NTYPES * 8;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_sb_encode
+ *
+ * Purpose: Encode driver information for the superblock. The NAME
+ * argument is a nine-byte buffer which will be initialized with
+ * an eight-character name/version number and null termination.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 16, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_sb_encode(H5FD_t *_file, char *name/*out*/,
+ unsigned char *buf/*out*/)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mt;
+ haddr_t memb_eoa;
+
+ /* Name and version number */
+ strcpy(name, "NCSAmulti");
+
+ /* Copy EOA values into buffer */
+ assert(sizeof(haddr_t)<=8);
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (file->memb[mt]) {
+ memb_eoa = H5FDget_eoa(file->memb[mt]);
+ } else {
+ memb_eoa = HADDR_UNDEF;
+ }
+ memcpy(buf+mt*sizeof(memb_eoa), &memb_eoa, sizeof(memb_eoa));
+ }
+
+ /* Convert to destination type */
+ if (H5Tconvert(H5T_NATIVE_HADDR, H5T_STD_U64LE, H5FD_MEM_NTYPES,
+ buf, NULL, H5P_DEFAULT)<0) return -1;
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_sb_decode
+ *
+ * Purpose: Decodes the superblock information for this driver. The NAME
+ * argument is the eight-character (plus null termination) name
+ * stored in the file.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 16, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mt;
+ char x[H5FD_MEM_NTYPES*8];
+
+ /* Make sure the name/version number is correct */
+ if (strcmp(name, "NCSAmult")) return -1;
+
+ /* Decode EOA values */
+ assert(sizeof(haddr_t)<=8);
+ memcpy(x, buf, H5FD_MEM_NTYPES*8);
+ if (H5Tconvert(H5T_STD_U64LE, H5T_NATIVE_HADDR, H5FD_MEM_NTYPES,
+ x, NULL, H5P_DEFAULT)<0) return -1;
+
+ /* Set EOA values */
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (file->memb[mt]) {
+ H5FDset_eoa(file->memb[mt], ((haddr_t*)x)[mt]);
+ }
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_fapl_get
+ *
+ * Purpose: Returns a file access property list which indicates how the
+ * specified file is being accessed. The return list could be
+ * used to access another file the same way.
+ *
+ * Return: Success: Ptr to new file access property list with all
+ * members copied from the file struct.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Friday, August 13, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_multi_fapl_get(H5FD_t *_file)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_multi_fapl_t fa;
+
+ memset(&fa, 0, sizeof fa);
+ memcpy(fa.memb_map, file->memb_map, sizeof(fa.memb_map));
+ memcpy(fa.memb_fapl, file->memb_fapl, sizeof(fa.memb_fapl));
+ memcpy(fa.memb_name, file->memb_name, sizeof(fa.memb_name));
+ memcpy(fa.memb_addr, file->memb_addr, sizeof(fa.memb_addr));
+ return H5FD_multi_fapl_copy(&fa);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_fapl_copy
+ *
+ * Purpose: Copies the multi-specific file access properties.
+ *
+ * Return: Success: Ptr to a new property list
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_multi_fapl_copy(const void *_old_fa)
+{
+ const H5FD_multi_fapl_t *old_fa = (const H5FD_multi_fapl_t*)_old_fa;
+ H5FD_multi_fapl_t *new_fa = malloc(sizeof(H5FD_multi_fapl_t));
+ H5FD_mem_t mt;
+ int nerrors = 0;
+
+ assert(new_fa);
+
+ memcpy(new_fa, old_fa, sizeof(H5FD_multi_fapl_t));
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (old_fa->memb_fapl[mt]>=0) {
+ new_fa->memb_fapl[mt] = H5Pcopy(old_fa->memb_fapl[mt]);
+ if (new_fa->memb_fapl[mt]<0) nerrors++;
+ }
+ if (old_fa->memb_name[mt]) {
+ new_fa->memb_name[mt] = malloc(strlen(old_fa->memb_name[mt])+1);
+ assert(new_fa->memb_name[mt]);
+ strcpy(new_fa->memb_name[mt], old_fa->memb_name[mt]);
+ }
+ }
+
+ if (nerrors) {
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (new_fa->memb_fapl[mt]>=0) H5Pclose(new_fa->memb_fapl[mt]);
+ if (new_fa->memb_name[mt]) free(new_fa->memb_name[mt]);
+ }
+ free(new_fa);
+ return NULL;
+ }
+ return new_fa;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_fapl_free
+ *
+ * Purpose: Frees the multi-specific file access properties.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_fapl_free(void *_fa)
+{
+ H5FD_multi_fapl_t *fa = (H5FD_multi_fapl_t*)_fa;
+ H5FD_mem_t mt;
+
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (fa->memb_fapl[mt]>=0) H5Pclose(fa->memb_fapl[mt]);
+ if (fa->memb_name[mt]) free(fa->memb_name[mt]);
+ }
+ free(fa);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_dxpl_copy
+ *
+ * Purpose: Copes the multi-specific data transfer properties.
+ *
+ * Return: Success: Ptr to new property list
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_multi_dxpl_copy(const void *_old_dx)
+{
+ const H5FD_multi_dxpl_t *old_dx = (const H5FD_multi_dxpl_t*)_old_dx;
+ H5FD_multi_dxpl_t *new_dx = malloc(sizeof(H5FD_multi_dxpl_t));
+ H5FD_mem_t mt;
+ int nerrors = 0;
+
+ assert(new_dx);
+
+ memcpy(new_dx, old_dx, sizeof(H5FD_multi_dxpl_t));
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (old_dx->memb_dxpl[mt]>=0) {
+ new_dx->memb_dxpl[mt] = H5Pcopy(old_dx->memb_dxpl[mt]);
+ if (new_dx->memb_dxpl[mt]<0) nerrors++;
+ }
+ }
+
+ if (nerrors) {
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ H5Pclose(new_dx->memb_dxpl[mt]);
+ }
+ free(new_dx);
+ return NULL;
+ }
+ return new_dx;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_dxpl_free
+ *
+ * Purpose: Frees the multi-specific data transfer properties.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_dxpl_free(void *_dx)
+{
+ H5FD_multi_dxpl_t *dx = (H5FD_multi_dxpl_t*)_dx;
+ H5FD_mem_t mt;
+
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (dx->memb_dxpl[mt]>=0) H5Pclose(dx->memb_dxpl[mt]);
+ }
+ free(dx);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_open
+ *
+ * Purpose: Creates and/or opens a multi 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: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_multi_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr)
+{
+ H5FD_multi_t *file=NULL;
+ H5FD_mem_t mt, mmt, mt2, mmt2;
+ char tmp[4096];
+ int seen[H5FD_MEM_NTYPES];
+
+ /* Check arguments */
+ if (!name || !*name) return NULL;
+ if (0==maxaddr || HADDR_UNDEF==maxaddr) return NULL;
+
+ /*
+ * Initialize file from file access properties. The default mapping
+ * creates two files -- one for meta data and one for raw data. The
+ * default file extensions are ".meta" and ".raw" accessed by default
+ * file drivers. Half the address space is used for each.
+ */
+ if (NULL==(file=calloc(1, sizeof(H5FD_multi_t)))) return NULL;
+ if (H5P_DEFAULT==fapl_id || H5FD_MULTI!=H5Pget_driver(fapl_id)) {
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ file->memb_map[mt] = H5FD_MEM_DRAW==mt?mt:H5FD_MEM_SUPER;
+ file->memb_addr[mt] = HADDR_UNDEF;
+ file->memb_fapl[mt] = H5P_DEFAULT;
+ }
+ file->memb_name[H5FD_MEM_SUPER] = my_strdup("%s.meta");
+ file->memb_addr[H5FD_MEM_SUPER] = 0;
+
+ file->memb_name[H5FD_MEM_DRAW] = my_strdup("%s.raw");
+ file->memb_addr[H5FD_MEM_DRAW] = maxaddr/2;
+ } else {
+ H5FD_multi_fapl_t *fa = H5Pget_driver_info(fapl_id);
+ assert(fa);
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ file->memb_map[mt] = fa->memb_map[mt];
+ file->memb_addr[mt] = fa->memb_addr[mt];
+ if (fa->memb_fapl[mt]>=0) {
+ file->memb_fapl[mt] = H5Pcopy(fa->memb_fapl[mt]);
+ } else {
+ file->memb_fapl[mt] = fa->memb_fapl[mt];
+ }
+ if (fa->memb_name[mt]) {
+ file->memb_name[mt] = my_strdup(fa->memb_name[mt]);
+ } else {
+ file->memb_name[mt] = NULL;
+ }
+ }
+ }
+ file->flags = flags;
+
+ /*
+ * Figure out the memb_next[] values for each member. This is the
+ * beginning address of the next member.
+ */
+ memset(seen, 0, sizeof seen);
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ mmt = file->memb_map[mt];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+ assert(mmt>0 && mmt<H5FD_MEM_NTYPES);
+ if (seen[mmt]++) continue;
+
+ file->memb_next[mmt] = HADDR_UNDEF;
+ for (mt2=1; mt2<H5FD_MEM_NTYPES; mt2++) {
+ mmt2 = file->memb_map[mt2];
+ if (H5FD_MEM_DEFAULT==mmt2) mmt2 = mt2;
+ assert(mmt2>0 && mmt2<H5FD_MEM_NTYPES);
+ if (mmt==mmt2) continue;
+
+ if (file->memb_addr[mmt]<file->memb_addr[mmt2] &&
+ (HADDR_UNDEF==file->memb_next[mmt] ||
+ file->memb_next[mmt]>file->memb_addr[mmt2])) {
+ file->memb_next[mmt] = file->memb_addr[mmt2];
+ }
+ }
+ }
+
+ /*
+ * Open all the multi members.
+ */
+ memset(seen, 0, sizeof seen);
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ mmt = file->memb_map[mt];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+ assert(mmt>0 && mmt<H5FD_MEM_NTYPES);
+ if (seen[mmt]++) continue;
+ assert(file->memb_name[mmt]);
+ sprintf(tmp, file->memb_name[mmt], name);
+
+#ifdef H5FD_MULTI_DEBUG
+ if (file->flags & H5F_ACC_DEBUG) {
+ fprintf(stderr, "H5FD_MULTI: opening \"%s\"\n", tmp);
+ }
+#endif
+ H5E_BEGIN_TRY {
+ file->memb[mmt] = H5FDopen(tmp, flags, file->memb_fapl[mmt],
+ HADDR_UNDEF);
+ } H5E_END_TRY;
+ if (!file->memb[mmt]) {
+#ifdef H5FD_MULTI_DEBUG
+ if (file->flags & H5F_ACC_DEBUG) {
+ fprintf(stderr, "H5FD_MULTI: open failed\n");
+ }
+#endif
+ goto error;
+ }
+ }
+
+ /* Write index file */
+ if ((flags & H5F_ACC_RDWR) &&
+ H5FD_multi_flush((H5FD_t*)file)<0) goto error;
+ return (H5FD_t*)file;
+
+ error:
+ /* Cleanup and fail */
+ if (file) {
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (file->memb[mt]) H5FDclose(file->memb[mt]);
+ if (file->memb_fapl[mt]>=0) H5Pclose(file->memb_fapl[mt]);
+ if (file->memb_name[mt]) free(file->memb_name[mt]);
+ }
+ free(file);
+ }
+ return NULL;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_close
+ *
+ * Purpose: Closes a multi file.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative with as many members closed as
+ * possible. The only subsequent operation
+ * permitted on the file is a close operation.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_close(H5FD_t *_file)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mt;
+ int nerrors=0;
+
+ /* Flush our own data */
+ if (H5FD_multi_flush(_file)<0) nerrors++;
+
+ /* Close as many members as possible */
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (file->memb[mt]) {
+#ifdef H5FD_MULTI_DEBUG
+ if (file->flags & H5F_ACC_DEBUG) {
+ fprintf(stderr, "H5FD_MULTI: closing member %d\n", (int)mt);
+ }
+#endif
+ if (H5FDclose(file->memb[mt])<0) {
+#ifdef H5FD_MULTI_DEBUG
+ if (file->flags & H5F_ACC_DEBUG) {
+ fprintf(stderr, "H5FD_MULTI: close failed\n");
+ }
+#endif
+ nerrors++;
+ } else {
+ file->memb[mt] = NULL;
+ }
+ }
+ }
+ if (nerrors) return -1;
+
+ /* Clean up other stuff */
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (file->memb_fapl[mt]>=0) H5Pclose(file->memb_fapl[mt]);
+ if (file->memb_name[mt]) free(file->memb_name[mt]);
+ }
+ free(file);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_cmp
+ *
+ * Purpose: Compares two file families to see if they are the same. It
+ * does this by comparing the first common member of the two
+ * families. If the families have no members in common then the
+ * file with the earliest member is smaller than the other file.
+ * We abort if neither file has any members.
+ *
+ * Return: Success: like strcmp()
+ *
+ * Failure: never fails (arguments were checked by the
+ * caller).
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_multi_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_multi_t *f1 = (const H5FD_multi_t*)_f1;
+ const H5FD_multi_t *f2 = (const H5FD_multi_t*)_f2;
+ H5FD_mem_t mt;
+ int cmp=0;
+
+ for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
+ if (f1->memb[mt] && f2->memb[mt]) break;
+ if (!cmp) {
+ if (f1->memb[mt]) cmp = -1;
+ else if (f2->memb[mt]) cmp = 1;
+ }
+ }
+ assert(cmp || mt<H5FD_MEM_NTYPES);
+ if (mt>=H5FD_MEM_NTYPES) return cmp;
+
+ return H5FDcmp(f1->memb[mt], f2->memb[mt]);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_get_eoa
+ *
+ * Purpose: Returns 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: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_multi_get_eoa(H5FD_t *_file)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ return file->eoa;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file by savig the new
+ * EOA value in the file struct. Also set the EOA marker for the
+ * subfile in which the new EOA value falls. We don't set the
+ * EOA values of any other subfiles.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_set_eoa(H5FD_t *_file, haddr_t eoa)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mt, mmt;
+ herr_t status;
+
+ /* Find the subfile in which the new EOA value falls */
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ mmt = file->memb_map[mt];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+ assert(mmt>0 && mmt<H5FD_MEM_NTYPES);
+
+ if (eoa>=file->memb_addr[mmt] && eoa<file->memb_next[mmt]) {
+ break;
+ }
+ }
+ assert(mt<H5FD_MEM_NTYPES);
+
+ /* Set subfile eoa */
+ H5E_BEGIN_TRY {
+ status = H5FDset_eoa(file->memb[mmt], eoa-file->memb_addr[mmt]);
+ } H5E_END_TRY;
+ if (status<0) return -1;
+
+ /* Save new eoa for return later */
+ file->eoa = eoa;
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_get_eof
+ *
+ * Purpose: Returns the end-of-file marker, which is the greater of
+ * either the total multi size or the current EOA marker.
+ *
+ * Return: Success: End of file address, the first address past
+ * the end of the multi of files or the current
+ * EOA, whichever is larger.
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_multi_get_eof(H5FD_t *_file)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ haddr_t eof=0, tmp;
+ H5FD_mem_t mt, mmt;
+ int seen[H5FD_MEM_NTYPES];
+
+ memset(seen, 0, sizeof seen);
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ mmt = file->memb_map[mt];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+ assert(mmt>0 && mmt<H5FD_MEM_NTYPES);
+ if (seen[mmt]++) continue;
+
+ H5E_BEGIN_TRY {
+ tmp = H5FDget_eof(file->memb[mmt]);
+ } H5E_END_TRY;
+ if (HADDR_UNDEF==tmp) return HADDR_UNDEF;
+ if (tmp>0) tmp += file->memb_addr[mmt];
+ if (tmp>eof) eof = tmp;
+ }
+
+ return MAX(file->eoa, eof);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_alloc
+ *
+ * Purpose: Allocate file memory.
+ *
+ * Return: Success: Address of new memory
+ *
+ * Failure: HADDR_UNDEF
+ *
+ * Programmer: Robb Matzke
+ * Thursday, August 12, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_multi_alloc(H5FD_t *_file, H5FD_mem_t type, hsize_t size)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mmt;
+ haddr_t addr;
+
+ mmt = file->memb_map[type];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = type;
+
+ if (HADDR_UNDEF==(addr=H5FDalloc(file->memb[mmt], type, size))) {
+ return HADDR_UNDEF;
+ }
+ addr += file->memb_addr[mmt];
+ if (addr+size>file->eoa) file->eoa = addr+size;
+ return addr;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_free
+ *
+ * Purpose: Frees memory
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Thursday, August 12, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_free(H5FD_t *_file, H5FD_mem_t type, haddr_t addr, hsize_t size)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mmt;
+
+ mmt = file->memb_map[type];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = type;
+
+ assert(addr>=file->memb_addr[mmt]);
+ assert(addr+size<=file->memb_next[mmt]);
+ return H5FDfree(file->memb[mmt], type, addr-file->memb_addr[mmt], size);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_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: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_read(H5FD_t *_file, hid_t dxpl_id, haddr_t addr, hsize_t size,
+ void *_buf/*out*/)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_multi_dxpl_t *dx=NULL;
+ H5FD_mem_t mt, mmt, hi=H5FD_MEM_DEFAULT;
+ haddr_t start_addr=0;
+
+ /* Get the data transfer properties */
+ if (H5P_DEFAULT!=dxpl_id && H5FD_MULTI==H5Pget_driver(dxpl_id)) {
+ dx = H5Pget_driver_info(dxpl_id);
+ }
+
+ /* Find the file to which this address belongs */
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ mmt = file->memb_map[mt];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+ assert(mmt>0 && mmt<H5FD_MEM_NTYPES);
+
+ if (file->memb_addr[mmt]>addr) continue;
+ if (file->memb_addr[mmt]>=start_addr) {
+ start_addr = file->memb_addr[mmt];
+ hi = mmt;
+ }
+ }
+ assert(hi>0);
+
+ /* Read from that member */
+ return H5FDread(file->memb[hi], dx?dx->memb_dxpl[hi]:H5P_DEFAULT,
+ addr-start_addr, size, _buf);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_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: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_write(H5FD_t *_file, hid_t dxpl_id, haddr_t addr, hsize_t size,
+ const void *_buf)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_multi_dxpl_t *dx=NULL;
+ H5FD_mem_t mt, mmt, hi=H5FD_MEM_DEFAULT;
+ haddr_t start_addr=0;
+
+ /* Get the data transfer properties */
+ if (H5P_DEFAULT!=dxpl_id && H5FD_MULTI==H5Pget_driver(dxpl_id)) {
+ dx = H5Pget_driver_info(dxpl_id);
+ }
+
+ /* Find the file to which this address belongs */
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ mmt = file->memb_map[mt];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+ assert(mmt>0 && mmt<H5FD_MEM_NTYPES);
+
+ if (file->memb_addr[mmt]>addr) continue;
+ if (file->memb_addr[mmt]>=start_addr) {
+ start_addr = file->memb_addr[mmt];
+ hi = mmt;
+ }
+ }
+ assert(hi>0);
+
+ /* Write to that member */
+ return H5FDwrite(file->memb[hi], dx?dx->memb_dxpl[hi]:H5P_DEFAULT,
+ addr-start_addr, size, _buf);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_multi_flush
+ *
+ * Purpose: Flushes all multi members.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1, as many files flushed as possible.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_multi_flush(H5FD_t *_file)
+{
+ H5FD_multi_t *file = (H5FD_multi_t*)_file;
+ H5FD_mem_t mt, mmt;
+ int nerrors=0;
+
+#if 0
+ /* Debugging stuff... */
+ fprintf(stderr, "multifile access information:\n");
+
+ /* print the map */
+ fprintf(stderr, " map=");
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ mmt = file->memb_map[mt];
+ if (H5FD_MEM_DEFAULT==mmt) mmt = mt;
+ fprintf(stderr, "%s%d", 1==mt?"":",", (int)mmt);
+ }
+ fprintf(stderr, "\n");
+
+ /* print info about each file */
+ fprintf(stderr, " File Starting Allocated Next Member\n");
+ fprintf(stderr, " Number Address Size Address Name\n");
+ fprintf(stderr, " ------ -------------------- -------------------- -------------------- ------------------------------\n");
+
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ if (HADDR_UNDEF!=file->memb_addr[mt]) {
+ haddr_t eoa = H5FDget_eoa(file->memb[mt]);
+ fprintf(stderr, " %6d %20llu %20llu %20llu %s\n",
+ (int)mt, (unsigned long long)(file->memb_addr[mt]),
+ (unsigned long long)eoa,
+ (unsigned long long)(file->memb_next[mt]),
+ file->memb_name[mt]);
+ }
+ }
+#endif
+
+ /* Flush each file */
+ for (mt=1; mt<H5FD_MEM_NTYPES; mt++) {
+ if (file->memb[mt]) {
+ H5E_BEGIN_TRY {
+ if (H5FDflush(file->memb[mt])<0) nerrors++;
+ } H5E_END_TRY;
+ }
+ }
+
+ return nerrors ? -1 : 0;
+}
+