Files
hdf5/src/H5FDsplitter.c
Jacob Smith 6462c67b65 Patch a few holes in the Splitter VFD implementation.
* Missing logfile close on driver-open failure.
* Initialize empty string in test/vfd (logfile path in W/O compat check).
2020-05-29 14:27:14 -05:00

1471 lines
50 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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() */