diff options
Diffstat (limited to 'src/H5FDsplitter.c')
-rw-r--r-- | src/H5FDsplitter.c | 1470 |
1 files changed, 1470 insertions, 0 deletions
diff --git a/src/H5FDsplitter.c b/src/H5FDsplitter.c new file mode 100644 index 0000000..4ed3c4a --- /dev/null +++ b/src/H5FDsplitter.c @@ -0,0 +1,1470 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: The Splitter VFD implements a file driver which relays all the + * VFD calls to an underlying VFD, and send all the write calls to + * another underlying VFD. Maintains two files simultaneously. + */ + +/* This source code file is part of the H5FD driver module */ +#include "H5FDdrvr_module.h" + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fprivate.h" /* File access */ +#include "H5FDprivate.h" /* File drivers */ +#include "H5FDsplitter.h" /* Splitter file driver */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5FDsec2.h" /* Generic Functions */ +#include "H5FDstdio.h" /* Generic Functions */ +#include "H5Pprivate.h" /* Property lists */ + +/* The driver identification number, initialized at runtime */ +static hid_t H5FD_SPLITTER_g = 0; + +/* Driver-specific file access properties */ +typedef struct H5FD_splitter_fapl_t { + hid_t rw_fapl_id; /* fapl for the R/W channel */ + hid_t wo_fapl_id; /* fapl for the W/O channel */ + char wo_path[H5FD_SPLITTER_PATH_MAX + 1]; /* file name for the W/O channel */ + char log_file_path[H5FD_SPLITTER_PATH_MAX + 1]; /* file to record errors reported by the W/O channel */ + hbool_t ignore_wo_errs; /* TRUE to ignore errors on the W/O channel */ +} H5FD_splitter_fapl_t; + +/* The information of this splitter */ +typedef struct H5FD_splitter_t { + H5FD_t pub; /* public stuff, must be first */ + unsigned version; /* version of the H5FD_splitter_vfd_config_t structure used */ + H5FD_splitter_fapl_t fa; /* driver-specific file access properties */ + H5FD_t *rw_file; /* pointer of R/W channel */ + H5FD_t *wo_file; /* pointer of W/O channel */ + FILE *logfp; /* Log file pointer */ +} H5FD_splitter_t; + +/* + * These macros check for overflow of various quantities. These macros + * assume that HDoff_t is signed and haddr_t and size_t are unsigned. + * + * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t' + * is too large to be represented by the second argument + * of the file seek function. + * + * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too + * large to be represented by the `size_t' type. + * + * REGION_OVERFLOW: Checks whether an address and size pair describe data + * which can be addressed entirely by the second + * argument of the file seek function. + */ +#define MAXADDR (((haddr_t)1<<(8*sizeof(HDoff_t)-1))-1) +#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || ((A) & ~(haddr_t)MAXADDR)) +#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR) +#define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \ + HADDR_UNDEF==(A)+(Z) || \ + (HDoff_t)((A)+(Z))<(HDoff_t)(A)) + +/* This macro provides a wrapper for shared fail-log-ignore behavior + * for errors arising in the splitter's W/O channel. + * Logs an error entry in a log file, if the file exists. + * If not set to ignore errors, registers an error with the library. + */ +#define H5FD_SPLITTER_WO_ERROR(file, funcname, errmajor, errminor, ret, mesg) \ +{ \ + H5FD__splitter_log_error((file), (funcname), (mesg)); \ + if (FALSE == (file)->fa.ignore_wo_errs) { \ + HGOTO_ERROR((errmajor), (errminor), (ret), (mesg)) \ + } \ +} + +#define H5FD_SPLITTER_DEBUG_OP_CALLS 0 /* debugging print toggle; 0 disables */ + +#if H5FD_SPLITTER_DEBUG_OP_CALLS +#define H5FD_SPLITTER_LOG_CALL(name) do { \ + HDprintf("called %s()\n", (name)); \ + fflush(stdout); \ +} while (0) +#else +#define H5FD_SPLITTER_LOG_CALL(name) /* no-op */ +#endif /* H5FD_SPLITTER_DEBUG_OP_CALLS */ + +/* Private functions */ + +/* Print error messages from W/O channel to log file */ +static herr_t H5FD__splitter_log_error(const H5FD_splitter_t *file, const char *atfunc, const char *msg); + +static int H5FD__copy_plist(hid_t fapl_id, hid_t *id_out_ptr); + +/* Prototypes */ +static herr_t H5FD_splitter_term(void); +static hsize_t H5FD_splitter_sb_size(H5FD_t *_file); +static herr_t H5FD_splitter_sb_encode(H5FD_t *_file, char *name/*out*/, unsigned char *buf/*out*/); +static herr_t H5FD_splitter_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf); +static void *H5FD_splitter_fapl_get(H5FD_t *_file); +static void *H5FD_splitter_fapl_copy(const void *_old_fa); +static herr_t H5FD_splitter_fapl_free(void *_fapl); +static H5FD_t *H5FD_splitter_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr); +static herr_t H5FD_splitter_close(H5FD_t *_file); +static int H5FD_splitter_cmp(const H5FD_t *_f1, const H5FD_t *_f2); +static herr_t H5FD_splitter_query(const H5FD_t *_file, unsigned long *flags /* out */); +static herr_t H5FD_splitter_get_type_map(const H5FD_t *_file, H5FD_mem_t *type_map); +static haddr_t H5FD_splitter_alloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size); +static herr_t H5FD_splitter_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size); +static haddr_t H5FD_splitter_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type); +static herr_t H5FD_splitter_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr); +static haddr_t H5FD_splitter_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type); +static herr_t H5FD_splitter_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl, void** file_handle); +static herr_t H5FD_splitter_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, void *buf); +static herr_t H5FD_splitter_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, const void *buf); +static herr_t H5FD_splitter_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); +static herr_t H5FD_splitter_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); +static herr_t H5FD_splitter_lock(H5FD_t *_file, hbool_t rw); +static herr_t H5FD_splitter_unlock(H5FD_t *_file); + +static const H5FD_class_t H5FD_splitter_g = { + "splitter", /* name */ + MAXADDR, /* maxaddr */ + H5F_CLOSE_WEAK, /* fc_degree */ + H5FD_splitter_term, /* terminate */ + H5FD_splitter_sb_size, /* sb_size */ + H5FD_splitter_sb_encode, /* sb_encode */ + H5FD_splitter_sb_decode, /* sb_decode */ + sizeof(H5FD_splitter_fapl_t), /* fapl_size */ + H5FD_splitter_fapl_get, /* fapl_get */ + H5FD_splitter_fapl_copy, /* fapl_copy */ + H5FD_splitter_fapl_free, /* fapl_free */ + 0, /* dxpl_size */ + NULL, /* dxpl_copy */ + NULL, /* dxpl_free */ + H5FD_splitter_open, /* open */ + H5FD_splitter_close, /* close */ + H5FD_splitter_cmp, /* cmp */ + H5FD_splitter_query, /* query */ + H5FD_splitter_get_type_map, /* get_type_map */ + H5FD_splitter_alloc, /* alloc */ + H5FD_splitter_free, /* free */ + H5FD_splitter_get_eoa, /* get_eoa */ + H5FD_splitter_set_eoa, /* set_eoa */ + H5FD_splitter_get_eof, /* get_eof */ + H5FD_splitter_get_handle, /* get_handle */ + H5FD_splitter_read, /* read */ + H5FD_splitter_write, /* write */ + H5FD_splitter_flush, /* flush */ + H5FD_splitter_truncate, /* truncate */ + H5FD_splitter_lock, /* lock */ + H5FD_splitter_unlock, /* unlock */ + H5FD_FLMAP_DICHOTOMY /* fl_map */ +}; + +/* Declare a free list to manage the H5FD_splitter_t struct */ +H5FL_DEFINE_STATIC(H5FD_splitter_t); + + +/*------------------------------------------------------------------------- + * Function: H5FD__init_package + * + * Purpose: Initializes any interface-specific data or routines. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__init_package(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + H5FD_SPLITTER_LOG_CALL("H5FD__init_package"); + + if (H5FD_splitter_init() < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize splitter VFD") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD__init_package() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_init + * + * Purpose: Initialize the splitter driver by registering it with the + * library. + * + * Return: Success: The driver ID for the splitter driver. + * Failure: Negative + *------------------------------------------------------------------------- + */ +hid_t +H5FD_splitter_init(void) +{ + hid_t ret_value = H5I_INVALID_HID; + + FUNC_ENTER_NOAPI(FAIL) + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_init"); + + if (H5I_VFL != H5I_get_type(H5FD_SPLITTER_g)) { + H5FD_SPLITTER_g = H5FDregister(&H5FD_splitter_g); + } + + ret_value = H5FD_SPLITTER_g; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_init() */ + + +/*--------------------------------------------------------------------------- + * Function: H5FD_splitter_term + * + * Purpose: Shut down the splitter VFD. + * + * Returns: SUCCEED (Can't fail) + *--------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_term(void) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_term"); + + /* Reset VFL ID */ + H5FD_SPLITTER_g = 0; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FD_splitter_term() */ + + + /*------------------------------------------------------------------------- + * Function: H5FD__copy_plist + * + * Purpose: Sanity-wrapped H5P_copy_plist() for each channel. + * Utility function for operation in multiple locations. + * + * Return: 0 on success, -1 on error. + *------------------------------------------------------------------------- + */ +static int +H5FD__copy_plist(hid_t fapl_id, + hid_t *id_out_ptr) +{ + int ret_value = 0; + H5P_genplist_t *plist_ptr = NULL; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD__copy_plist"); + + HDassert(id_out_ptr != NULL); + + if (FALSE == H5P_isa_class(fapl_id, H5P_FILE_ACCESS)) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, -1, "not a file access property list"); + } + + plist_ptr = (H5P_genplist_t *)H5I_object(fapl_id); + if (NULL == plist_ptr) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, -1, "unable to get property list"); + } + + *id_out_ptr = H5P_copy_plist(plist_ptr, FALSE); + if (H5I_INVALID_HID == *id_out_ptr) { + HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, -1, "unable to copy file access property list"); + } + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__copy_plist() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pset_fapl_splitter + * + * Purpose: Sets the file access property list to use the + * splitter driver. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_fapl_splitter(hid_t fapl_id, H5FD_splitter_vfd_config_t *vfd_config) +{ + H5FD_splitter_fapl_t info; + H5P_genplist_t *plist_ptr = NULL; + herr_t ret_value = SUCCEED; + + H5Eclear2(H5E_DEFAULT); + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*Dr", fapl_id, vfd_config); + + H5FD_SPLITTER_LOG_CALL("H5Pset_fapl_splitter"); + + if (H5FD_SPLITTER_MAGIC != vfd_config->magic) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid configuration (magic number mismatch)") + } + if (H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION != vfd_config->version) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invlaid config (version number mismatch)") + } + + if (NULL == (plist_ptr = (H5P_genplist_t *)H5I_object(fapl_id))) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a valid property list") + } + + + /* Make sure that the W/O channel supports write-only capability. + * Some drivers (e.g. family or multi) do revision of the superblock + * in-memory, causing problems in that channel. + * Uses the feature flag H5FD_FEAT_DEFAULT_VFD_COMPATIBLE as the + * determining attribute. + */ + if (H5P_DEFAULT != vfd_config->wo_fapl_id) { + H5FD_class_t *wo_driver = NULL; + H5FD_driver_prop_t wo_driver_prop; + H5P_genplist_t *wo_plist_ptr = NULL; + unsigned long wo_driver_flags = 0; + + wo_plist_ptr = (H5P_genplist_t *)H5I_object(vfd_config->wo_fapl_id); + if (NULL == wo_plist_ptr) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") + } + if (H5P_peek(wo_plist_ptr, H5F_ACS_FILE_DRV_NAME, &wo_driver_prop) < 0) { + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get driver ID & info") + } + wo_driver = (H5FD_class_t *)H5I_object(wo_driver_prop.driver_id); + if (NULL == wo_driver) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid driver ID in file access property list") + } + if (H5FD_driver_query(wo_driver, &wo_driver_flags) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't query VFD flags") + } + if (0 == (H5FD_FEAT_DEFAULT_VFD_COMPATIBLE & wo_driver_flags)) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unsuitable W/O driver") + } + } /* end if W/O VFD is non-default */ + + + info.ignore_wo_errs = vfd_config->ignore_wo_errs; + HDstrncpy(info.wo_path, vfd_config->wo_path, H5FD_SPLITTER_PATH_MAX); + HDstrncpy(info.log_file_path, vfd_config->log_file_path, H5FD_SPLITTER_PATH_MAX); + info.rw_fapl_id = H5P_FILE_ACCESS_DEFAULT; /* pre-set value */ + info.wo_fapl_id = H5P_FILE_ACCESS_DEFAULT; /* pre-set value */ + + /* Set non-default channel FAPL IDs in splitter configuration info */ + if (H5P_DEFAULT != vfd_config->rw_fapl_id) { + if (FALSE == H5P_isa_class(vfd_config->rw_fapl_id, H5P_FILE_ACCESS)) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list") + } + info.rw_fapl_id = vfd_config->rw_fapl_id; + } + if (H5P_DEFAULT != vfd_config->wo_fapl_id) { + if (FALSE == H5P_isa_class(vfd_config->wo_fapl_id, H5P_FILE_ACCESS)) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list") + } + info.wo_fapl_id = vfd_config->wo_fapl_id; + } + + ret_value = H5P_set_driver(plist_ptr, H5FD_SPLITTER, &info); + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pset_fapl_splitter() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pget_fapl_splitter + * + * Purpose: Returns information about the splitter file access property + * list through the structure config_out. + * + * Will fail if config_out is received without pre-set valid + * magic and version information. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +herr_t +H5Pget_fapl_splitter(hid_t fapl_id, H5FD_splitter_vfd_config_t *config_out) +{ + const H5FD_splitter_fapl_t *fapl_ptr = NULL; + H5P_genplist_t *plist_ptr = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*Dr", fapl_id, config_out); + + H5FD_SPLITTER_LOG_CALL("H5Pget_fapl_splitter"); + + /* Check arguments */ + if (TRUE != H5P_isa_class(fapl_id, H5P_FILE_ACCESS)) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") + } + if (config_out == NULL) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "config_out pointer is null") + } + if (H5FD_SPLITTER_MAGIC != config_out->magic) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "info-out pointer invalid (magic number mismatch)") + } + if (H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION != config_out->version) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "info-out pointer invalid (version unsafe)") + } + + /* Pre-set out FAPL IDs with intent to replace these values */ + config_out->rw_fapl_id = H5I_INVALID_HID; + config_out->wo_fapl_id = H5I_INVALID_HID; + + /* Check and get the splitter fapl */ + if (NULL == (plist_ptr = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") + } + if (H5FD_SPLITTER != H5P_peek_driver(plist_ptr)) { + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver") + } + if (NULL == (fapl_ptr = (const H5FD_splitter_fapl_t *)H5P_peek_driver_info(plist_ptr))) { + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unable to get specific-driver info") + } + + HDstrncpy(config_out->wo_path, fapl_ptr->wo_path, H5FD_SPLITTER_PATH_MAX); + HDstrncpy(config_out->log_file_path, fapl_ptr->log_file_path, H5FD_SPLITTER_PATH_MAX); + config_out->ignore_wo_errs = fapl_ptr->ignore_wo_errs; + + /* Copy R/W and W/O FAPLs */ + if (H5FD__copy_plist(fapl_ptr->rw_fapl_id, &(config_out->rw_fapl_id)) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't copy R/W FAPL"); + } + if (H5FD__copy_plist(fapl_ptr->wo_fapl_id, &(config_out->wo_fapl_id)) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't copy W/O FAPL"); + } + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pget_fapl_splitter() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_flush + * + * Purpose: Flushes all data to disk for both channels. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_flush(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t closing) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_flush"); + + /* Public API for dxpl "context" */ + if (H5FDflush(file->rw_file, dxpl_id, closing) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTFLUSH, FAIL, "unable to flush R/W file") + } + if (H5FDflush(file->wo_file, dxpl_id, closing) < 0) { + H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_flush", + H5E_VFL, H5E_CANTFLUSH, FAIL, + "unable to flush W/O file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_flush() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_read + * + * Purpose: Reads SIZE bytes of data from the R/W channel, beginning at + * address ADDR into buffer BUF according to data transfer + * properties in DXPL_ID. + * + * Return: Success: SUCCEED + * The read result is written into the BUF buffer + * which should be allocated by the caller. + * Failure: FAIL + * The contents of BUF are undefined. + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_read( + H5FD_t *_file, + H5FD_mem_t H5_ATTR_UNUSED type, + hid_t H5_ATTR_UNUSED dxpl_id, + haddr_t addr, + size_t size, + void *buf /*out*/) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_read"); + + HDassert(file && file->pub.cls); + HDassert(buf); + + /* Check for overflow conditions */ + if (!H5F_addr_defined(addr)) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr) + } + if (REGION_OVERFLOW(addr, size)) { + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr) + } + + /* Only read from R/W channel */ + /* Public API for dxpl "context" */ + if (H5FDread(file->rw_file, type, dxpl_id, addr, size, buf) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "Reading from R/W channel failed") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_write + * + * Purpose: Writes SIZE bytes of data to R/W and W/O channels, beginning + * at address ADDR from buffer BUF according to data transfer + * properties in DXPL_ID. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, const void *buf) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + H5P_genplist_t *plist_ptr = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_write"); + + if (NULL == (plist_ptr = (H5P_genplist_t *)H5I_object(dxpl_id))) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list") + } + + /* Write to each file */ + /* Public API for dxpl "context" */ + if (H5FDwrite(file->rw_file, type, dxpl_id, addr, size, buf) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "R/W file write failed") + } + if (H5FDwrite(file->wo_file, type, dxpl_id, addr, size, buf) < 0) { + H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_write", + H5E_VFL, H5E_WRITEERROR, FAIL, + "unable to write W/O file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_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 + *------------------------------------------------------------------------- + */ +static void * +H5FD_splitter_fapl_get(H5FD_t *_file) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + void *ret_value = NULL; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_fapl_get"); + + ret_value = H5FD_splitter_fapl_copy(&(file->fa)); + + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_fapl_copy + * + * Purpose: Copies the file access properties. + * + * Return: Success: Pointer to a new property list info structure. + * Failure: NULL + *------------------------------------------------------------------------- + */ +static void * +H5FD_splitter_fapl_copy(const void *_old_fa) +{ + const H5FD_splitter_fapl_t *old_fa_ptr = (const H5FD_splitter_fapl_t *)_old_fa; + H5FD_splitter_fapl_t *new_fa_ptr = NULL; + void *ret_value = NULL; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_fapl_copy"); + + HDassert(old_fa_ptr); + + new_fa_ptr = (H5FD_splitter_fapl_t *)H5MM_calloc(sizeof(H5FD_splitter_fapl_t)); + if (NULL == new_fa_ptr) { + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate log file FAPL") + } + + if (HDmemcpy(new_fa_ptr, old_fa_ptr, sizeof(H5FD_splitter_fapl_t)) == NULL) { + HGOTO_ERROR(H5E_ARGS, H5E_CANTCOPY, NULL, "unable to shallow-copy info") + } + if (HDstrncpy(new_fa_ptr->wo_path, old_fa_ptr->wo_path, H5FD_SPLITTER_PATH_MAX) == NULL) { + HGOTO_ERROR(H5E_ARGS, H5E_CANTCOPY, NULL, "unable to copy write-only channel file path") + } + if (HDstrncpy(new_fa_ptr->log_file_path, old_fa_ptr->log_file_path, H5FD_SPLITTER_PATH_MAX) == NULL) { + HGOTO_ERROR(H5E_ARGS, H5E_CANTCOPY, NULL, "unable to copy log file path") + } + + /* Copy R/W and W/O FAPLs */ + if (H5FD__copy_plist(old_fa_ptr->rw_fapl_id, &(new_fa_ptr->rw_fapl_id)) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't copy R/W FAPL"); + } + if (H5FD__copy_plist(old_fa_ptr->wo_fapl_id, &(new_fa_ptr->wo_fapl_id)) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't copy W/O FAPL"); + } + + ret_value = (void *)new_fa_ptr; + +done: + if (NULL == ret_value) { + if (new_fa_ptr) { + H5MM_free(new_fa_ptr); + } + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_fapl_copy() */ + + +/*-------------------------------------------------------------------------- + * Function: H5FD_splitter_fapl_free + * + * Purpose: Releases the file access lists + * + * Return: SUCCEED/FAIL + *-------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_fapl_free(void *_fapl) +{ + H5FD_splitter_fapl_t *fapl = (H5FD_splitter_fapl_t*)_fapl; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_fapl_free"); + + /* Check arguments */ + HDassert(fapl); + + if (H5I_dec_ref(fapl->rw_fapl_id) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close R/W FAPL ID") + } + if (H5I_dec_ref(fapl->wo_fapl_id) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close W/O FAPL ID") + } + + /* Free the property list */ + H5MM_free(fapl); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_fapl_free() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_open + * + * Purpose: Create and/or opens a file as an HDF5 file. + * + * Return: Success: A pointer to a new file data structure. The + * public fields will be initialized by the + * caller, which is always H5FD_open(). + * Failure: NULL + *------------------------------------------------------------------------- + */ +static H5FD_t * +H5FD_splitter_open(const char *name, unsigned flags, hid_t splitter_fapl_id, haddr_t maxaddr) +{ + H5FD_splitter_t *file_ptr = NULL; /* Splitter VFD info */ + const H5FD_splitter_fapl_t *fapl_ptr = NULL; /* Driver-specific property list */ + H5P_genplist_t *plist_ptr = NULL; + H5FD_t *ret_value = NULL; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_open"); + + /* Check arguments */ + if (!name || !*name) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name") + } + if (0 == maxaddr || HADDR_UNDEF == maxaddr) { + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr") + } + if (ADDR_OVERFLOW(maxaddr)) { + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr") + } + if ( (H5P_FILE_ACCESS_DEFAULT == splitter_fapl_id) || + (H5FD_SPLITTER != H5Pget_driver(splitter_fapl_id)) ) + { + /* presupposes that H5P_FILE_ACCESS_DEFAULT is not a splitter */ + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "driver is not splitter") + } + + file_ptr = (H5FD_splitter_t *)H5FL_CALLOC(H5FD_splitter_t); + if (NULL == file_ptr) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct") + } + file_ptr->fa.rw_fapl_id = H5I_INVALID_HID; + file_ptr->fa.wo_fapl_id = H5I_INVALID_HID; + + /* Get the driver-specific file access properties */ + plist_ptr = (H5P_genplist_t *)H5I_object(splitter_fapl_id); + if (NULL == plist_ptr) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list") + } + fapl_ptr = (const H5FD_splitter_fapl_t *)H5P_peek_driver_info(plist_ptr); + if (NULL == fapl_ptr) { + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "unable to get VFL driver info") + } + + /* Copy simpler info */ + if (HDstrncpy(file_ptr->fa.wo_path, fapl_ptr->wo_path, H5FD_SPLITTER_PATH_MAX) == NULL) { + HGOTO_ERROR(H5E_VFL, H5E_CANTCOPY, NULL, "unable to copy write-only path") + } + if (HDstrncpy(file_ptr->fa.log_file_path, fapl_ptr->log_file_path, H5FD_SPLITTER_PATH_MAX) == NULL) { + HGOTO_ERROR(H5E_VFL, H5E_CANTCOPY, NULL, "unable to copy logfile path") + } + file_ptr->fa.ignore_wo_errs = fapl_ptr->ignore_wo_errs; + + /* Copy R/W and W/O channel FAPLs. */ + if (H5FD__copy_plist(fapl_ptr->rw_fapl_id, &(file_ptr->fa.rw_fapl_id)) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't copy R/W FAPL"); + } + if (H5FD__copy_plist(fapl_ptr->wo_fapl_id, &(file_ptr->fa.wo_fapl_id)) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't copy W/O FAPL"); + } + + /* Prepare log file if necessary. + * If application wants to ignore the errors from W/O channel and + * provided a name for the log file, then open it + */ + if (!file_ptr->logfp) { + if (file_ptr->fa.log_file_path[0] != '\0') { + file_ptr->logfp = HDfopen(file_ptr->fa.log_file_path, "w"); + if (file_ptr->logfp == NULL) { + HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, NULL, "unable to open log file") + } + } /* end if logfile path given */ + } /* end if logfile pointer/handle does not exist */ + + file_ptr->rw_file = H5FD_open(name, flags, fapl_ptr->rw_fapl_id, HADDR_UNDEF); + if (!file_ptr->rw_file) { + HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, NULL, "unable to open R/W file") + } + + file_ptr->wo_file = H5FD_open(fapl_ptr->wo_path, flags, fapl_ptr->wo_fapl_id, HADDR_UNDEF); + if (!file_ptr->wo_file) { + H5FD_SPLITTER_WO_ERROR(file_ptr, "H5FD_splitter_open", + H5E_VFL, H5E_CANTOPENFILE, NULL, + "unable to open W/O file") + } + + ret_value = (H5FD_t*)file_ptr; + +done: + if (NULL == ret_value) { + if (file_ptr) { + if (H5I_INVALID_HID != file_ptr->fa.rw_fapl_id) { + H5I_dec_ref(file_ptr->fa.rw_fapl_id); + } + if (H5I_INVALID_HID != file_ptr->fa.wo_fapl_id) { + H5I_dec_ref(file_ptr->fa.wo_fapl_id); + } + if (file_ptr->rw_file) { + H5FD_close(file_ptr->rw_file); + } + if (file_ptr->wo_file) { + H5FD_close(file_ptr->wo_file); + } + if (file_ptr->logfp) { + HDfclose(file_ptr->logfp); + } + H5FL_FREE(H5FD_splitter_t, file_ptr); + } + } /* end if error */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_open() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_close + * + * Purpose: Closes files on both read-write and write-only channels. + * + * Return: Success: SUCCEED + * Failure: FAIL, file not closed. + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_close(H5FD_t *_file) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_close"); + + /* Sanity check */ + HDassert(file); + + if (H5I_dec_ref(file->fa.rw_fapl_id) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_ARGS, FAIL, "can't close R/W FAPL") + } + if (H5I_dec_ref(file->fa.wo_fapl_id) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_ARGS, FAIL, "can't close W/O FAPL") + } + + if (file->rw_file) { + if (H5FD_close(file->rw_file) == FAIL) { + HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "unable to close R/W file") + } + } + if (file->wo_file) { + if (H5FD_close(file->wo_file) == FAIL) { + H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_close", + H5E_VFL, H5E_CANTCLOSEFILE, FAIL, + "unable to close W/O file") + } + } + + if (file->logfp) { + HDfclose(file->logfp); + file->logfp = NULL; + } + + /* Release the file info */ + file = H5FL_FREE(H5FD_splitter_t, file); + file = NULL; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_close() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_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 + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_splitter_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type) +{ + const H5FD_splitter_t *file = (const H5FD_splitter_t *)_file; + haddr_t ret_value = HADDR_UNDEF; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_get_eoa"); + + /* Sanity check */ + HDassert(file); + HDassert(file->rw_file); + + if ((ret_value = H5FD_get_eoa(file->rw_file, type)) == HADDR_UNDEF) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, HADDR_UNDEF, "unable to get eoa") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_get_eoa */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_set_eoa + * + * Purpose: Set the end-of-address marker for the file. This function is + * called shortly after an existing HDF5 file is opened in order + * to tell the driver where the end of the HDF5 data is located. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_set_eoa";) + + /* Sanity check */ + HDassert(file); + HDassert(file->rw_file); + HDassert(file->wo_file); + + if (H5FD_set_eoa(file->rw_file, type, addr) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "H5FDset_eoa failed for R/W file") + } + + if (H5FD_set_eoa(file->wo_file, type, addr) < 0) { + H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_set_eoa", + H5E_VFL, H5E_CANTSET, FAIL, + "unable to set EOA for W/O file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_set_eoa() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_get_eof + * + * 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 + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_splitter_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type) +{ + const H5FD_splitter_t *file = (const H5FD_splitter_t *)_file; + haddr_t ret_value = HADDR_UNDEF; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_get_eof"); + + /* Sanity check */ + HDassert(file); + HDassert(file->rw_file); + + if (HADDR_UNDEF == (ret_value = H5FD_get_eof(file->rw_file, type))) { + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, HADDR_UNDEF, "unable to get eof") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_get_eof */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_truncate + * + * Purpose: Notify driver to truncate the file back to the allocated size. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_truncate"); + + HDassert(file); + HDassert(file->rw_file); + HDassert(file->wo_file); + + if (H5FDtruncate(file->rw_file, dxpl_id, closing) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "unable to truncate R/W file") + } + + if (H5FDtruncate(file->wo_file, dxpl_id, closing) < 0) { + H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_truncate", + H5E_VFL, H5E_CANTUPDATE, FAIL, + "unable to truncate W/O file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_truncate */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_sb_size + * + * Purpose: Obtains the number of bytes required to store the driver file + * access data in the HDF5 superblock. + * + * Return: Success: Number of bytes required. + * + * Failure: 0 if an error occurs or if the driver has no + * data to store in the superblock. + * + * NOTE: no public API for H5FD_sb_size, it needs to be added + *------------------------------------------------------------------------- + */ +static hsize_t +H5FD_splitter_sb_size(H5FD_t *_file) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + hsize_t ret_value = 0; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_sb_size"); + + /* Sanity check */ + HDassert(file); + HDassert(file->rw_file); + + if (file->rw_file) { + ret_value = H5FD_sb_size(file->rw_file); + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_sb_size */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_sb_encode + * + * Purpose: Encode driver-specific data into the output arguments. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_sb_encode(H5FD_t *_file, char *name/*out*/, unsigned char *buf/*out*/) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_sb_encode"); + + /* Sanity check */ + HDassert(file); + HDassert(file->rw_file); + + if (file->rw_file && H5FD_sb_encode(file->rw_file, name, buf) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTENCODE, FAIL, "unable to encode the superblock in R/W file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_sb_encode */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_sb_decode + * + * Purpose: Decodes the driver information block. + * + * Return: SUCCEED/FAIL + * + * NOTE: no public API for H5FD_sb_size, need to add + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_sb_decode"); + + /* Sanity check */ + HDassert(file); + HDassert(file->rw_file); + + if (H5FD_sb_load(file->rw_file, name, buf) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "unable to decode the superblock in R/W file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_sb_decode */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_cmp + * + * Purpose: Compare the keys of two files. + * + * Return: Success: A value like strcmp() + * Failure: Must never fail + *------------------------------------------------------------------------- + */ +static int +H5FD_splitter_cmp(const H5FD_t *_f1, const H5FD_t *_f2) +{ + const H5FD_splitter_t *f1 = (const H5FD_splitter_t *)_f1; + const H5FD_splitter_t *f2 = (const H5FD_splitter_t *)_f2; + herr_t ret_value = 0; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_cmp"); + + HDassert(f1); + HDassert(f2); + + ret_value = H5FD_cmp(f1->rw_file, f2->rw_file); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_cmp */ + + +/*-------------------------------------------------------------------------- + * Function: H5FD_splitter_get_handle + * + * Purpose: Returns a pointer to the file handle of low-level virtual + * file driver. + * + * Return: SUCCEED/FAIL + *-------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_get_handle( + H5FD_t *_file, + hid_t H5_ATTR_UNUSED fapl, + void **file_handle) +{ + H5FD_splitter_t *file = (H5FD_splitter_t*)_file; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_get_handle"); + + /* Check arguments */ + HDassert(file); + HDassert(file->rw_file); + HDassert(file_handle); + + /* Only do for R/W channel */ + if (H5FD_get_vfd_handle(file->rw_file, file->fa.rw_fapl_id, file_handle) < 0) + { + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "unable to get handle of R/W file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_get_handle */ + + +/*-------------------------------------------------------------------------- + * Function: H5FD_splitter_lock + * + * Purpose: Sets a file lock. + * + * Return: SUCCEED/FAIL + *-------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_lock(H5FD_t *_file, hbool_t rw) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; /* VFD file struct */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_lock"); + + HDassert(file); + HDassert(file->rw_file); + + /* Place the lock on each file */ + if (H5FD_lock(file->rw_file, rw) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTLOCK, FAIL, "unable to lock R/W file") + } + if (file->wo_file != NULL) { + if (H5FD_lock(file->wo_file, rw) < 0) { + H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_lock", + H5E_VFL, H5E_CANTLOCK, FAIL, + "unable to lock W/O file") + } + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_lock */ + + +/*-------------------------------------------------------------------------- + * Function: H5FD_splitter_unlock + * + * Purpose: Removes a file lock. + * + * Return: SUCCEED/FAIL + *-------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_unlock(H5FD_t *_file) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; /* VFD file struct */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_unlock"); + + /* Check arguments */ + HDassert(file); + HDassert(file->rw_file); + + /* Remove the lock on each file */ + if (H5FD_unlock(file->rw_file) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTUNLOCK, FAIL, "unable to unlock R/W file") + } + if (file->wo_file != NULL) { + if (H5FD_unlock(file->wo_file) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTUNLOCK, FAIL, + "unable to unlock W/O file") + } + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_unlock */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_query + * + * Purpose: Set the flags that this VFL driver is capable of supporting. + * (listed in H5FDpublic.h) + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_query(const H5FD_t *_file, unsigned long *flags /* out */) +{ + const H5FD_splitter_t *file = (const H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_query"); + + if (file) { + HDassert(file); + HDassert(file->rw_file); + + if (H5FDquery(file->rw_file, flags) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTLOCK, FAIL, + "unable to query R/W file"); + } + } + else { + /* There is no file. Because this is a pure passthrough VFD, + * it has no features of its own. + */ + if (flags) { + *flags = 0; + } + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_query() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_alloc + * + * Purpose: Allocate file memory. + * + * Return: Address of allocated space (HADDR_UNDEF if error). + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_splitter_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; /* VFD file struct */ + haddr_t ret_value = HADDR_UNDEF; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_alloc"); + + /* Check arguments */ + HDassert(file); + HDassert(file->rw_file); + + /* Allocate memory for each file, only return the return value for R/W file. */ + if ((ret_value = H5FDalloc(file->rw_file, type, dxpl_id, size)) == HADDR_UNDEF) { + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "unable to allocate for R/W file") + } + + if (H5FDalloc(file->wo_file, type, dxpl_id, size) == HADDR_UNDEF) { + H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_alloc", + H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, + "unable to alloc for W/O file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_alloc() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_get_type_map + * + * Purpose: Retrieve the memory type mapping for this file + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_get_type_map(const H5FD_t *_file, H5FD_mem_t *type_map) +{ + const H5FD_splitter_t *file = (const H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_get_type_map"); + + /* Check arguments */ + HDassert(file); + HDassert(file->rw_file); + + /* Retrieve memory type mapping for R/W channel only */ + if (H5FD_get_fs_type_map(file->rw_file, type_map) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "unable to allocate for R/W file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_get_type_map() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_splitter_free + * + * Purpose: Free the resources for the splitter VFD. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_splitter_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; /* VFD file struct */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + H5FD_SPLITTER_LOG_CALL("H5FD_splitter_free"); + + /* Check arguments */ + HDassert(file); + HDassert(file->rw_file); + + if (H5FDfree(file->rw_file, type, dxpl_id, addr, size) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "unable to free for R/W file") + } + + if (H5FDfree(file->wo_file, type, dxpl_id, addr, size) < 0) { + H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_free", + H5E_VFL, H5E_CANTINIT, FAIL, + "unable to free for W/O file") + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_splitter_free() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD__splitter_log_error + * + * Purpose: Log an error from the W/O channel appropriately. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__splitter_log_error(const H5FD_splitter_t *file, const char *atfunc, const char *msg) +{ + size_t size = 0; + char *s = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC_NOERR + + H5FD_SPLITTER_LOG_CALL("H5FD__splitter_log_error"); + + /* Check arguments */ + HDassert(file); + HDassert(atfunc && *atfunc); + HDassert(msg && *msg); + + if (file->logfp != NULL) { + size = strlen(atfunc) + strlen(msg) + 3; /* ':', ' ', '\n' */ + s = (char *)malloc(sizeof(char) * (size+1)); + if (NULL == s) { + ret_value = FAIL; + } + else + if (size < (size_t)HDsnprintf(s, size+1, "%s: %s\n", atfunc, msg)) { + ret_value = FAIL; + } + else + if (size != HDfwrite(s, 1, size, file->logfp)) { + ret_value = FAIL; + } + HDfree(s); + } + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD__splitter_log_error() */ + |