summaryrefslogtreecommitdiffstats
path: root/src/H5FDmulti.c
diff options
context:
space:
mode:
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;
+}
+