Files
hdf5/src/H5FDmirror.c
Quincey Koziol ba087ce2b5 Clean up private / package / static namespace issues (function naming, which
header file, FUNC_ENTER / LEAVE, etc).  Removed remaining personal email
addresses from library source code (still needs cleaned from other directories).
Misc. warning, style, and whitespace cleanup.
2020-08-22 14:00:44 -05:00

2018 lines
71 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: Transmit write-only operations to a receiver/writer process on
* a remote host.
*/
#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
#include "H5private.h" /* Generic Functions */
#ifdef H5_HAVE_MIRROR_VFD
#include "H5Eprivate.h" /* Error handling */
#include "H5Fprivate.h" /* File access */
#include "H5FDprivate.h" /* File drivers */
#include "H5FDmirror.h" /* "Mirror" definitions */
#include "H5FDmirror_priv.h" /* Private header for the mirror VFD */
#include "H5FLprivate.h" /* Free Lists */
#include "H5Iprivate.h" /* IDs */
#include "H5MMprivate.h" /* Memory management */
#include "H5Pprivate.h" /* Property lists */
/* The driver identification number, initialized at runtime */
static hid_t H5FD_MIRROR_g = 0;
/* Virtual file structure for a Mirror Driver */
typedef struct H5FD_mirror_t {
H5FD_t pub; /* Public stuff, must be first */
H5FD_mirror_fapl_t fa; /* Configuration structure */
haddr_t eoa; /* End of allocated region */
haddr_t eof; /* End of file; current file size */
int sock_fd; /* Handle of socket to remote operator */
H5FD_mirror_xmit_t xmit; /* Primary communication header */
uint32_t xmit_i; /* Counter of transmission sent and rec'd */
} H5FD_mirror_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))
#ifndef BSWAP_64
#define BSWAP_64(X) \
(uint64_t)( (((X) & 0x00000000000000FF) << 56) \
| (((X) & 0x000000000000FF00) << 40) \
| (((X) & 0x0000000000FF0000) << 24) \
| (((X) & 0x00000000FF000000) << 8) \
| (((X) & 0x000000FF00000000) >> 8) \
| (((X) & 0x0000FF0000000000) >> 24) \
| (((X) & 0x00FF000000000000) >> 40) \
| (((X) & 0xFF00000000000000) >> 56))
#endif /* BSWAP_64 */
/* Debugging flabs for verbose tracing -- nonzero to enable */
#define MIRROR_DEBUG_OP_CALLS 0
#define MIRROR_DEBUG_XMIT_BYTES 0
#if MIRROR_DEBUG_XMIT_BYTES
#define LOG_XMIT_BYTES(label, buf, len) do { \
ssize_t bytes_written = 0; \
const unsigned char *b = NULL; \
\
HDfprintf(stdout, "%s bytes:\n```\n", (label)); \
\
/* print whole lines */ \
while ((len - bytes_written) >= 32) { \
b = (const unsigned char *)(buf) + bytes_written; \
HDfprintf(stdout, \
"%04zX %02X%02X%02X%02X %02X%02X%02X%02X" \
" %02X%02X%02X%02X %02X%02X%02X%02X" \
" %02X%02X%02X%02X %02X%02X%02X%02X" \
" %02X%02X%02X%02X %02X%02X%02X%02X\n", \
bytes_written, \
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], \
b[8], b[9], b[10],b[11], b[12],b[13],b[14],b[15], \
b[16],b[17],b[18],b[19], b[20],b[21],b[22],b[23], \
b[24],b[25],b[26],b[27], b[28],b[29],b[30],b[31]); \
bytes_written += 32; \
} \
\
/* start partial line */ \
if (len > bytes_written) { \
HDfprintf(stdout, "%04zX ", bytes_written); \
} \
\
/* partial line blocks */ \
while ((len - bytes_written) >= 4) { \
HDfprintf(stdout, " %02X%02X%02X%02X", \
(buf)[bytes_written], (buf)[bytes_written+1], \
(buf)[bytes_written+2], (buf)[bytes_written+3]); \
bytes_written += 4; \
} \
\
/* block separator before partial block */ \
if (len > bytes_written) { \
HDfprintf(stdout, " "); \
} \
\
/* partial block individual bytes */ \
while (len > bytes_written) { \
HDfprintf(stdout, "%02X", (buf)[bytes_written++]); \
} \
\
/* end partial line */ \
HDfprintf(stdout, "\n"); \
HDfprintf(stdout, "```\n"); \
HDfflush(stdout); \
} while (0)
#else
#define LOG_XMIT_BYTES(label, buf, len) /* no-op */
#endif /* MIRROR_DEBUG_XMIT_BYTE */
#if MIRROR_DEBUG_OP_CALLS
#define LOG_OP_CALL(name) do { \
HDprintf("called %s()\n", (name)); \
HDfflush(stdout); \
} while (0)
#else
#define LOG_OP_CALL(name) /* no-op */
#endif /* MIRROR_DEBUG_OP_CALLS */
/* Prototypes */
static herr_t H5FD__mirror_term(void);
static void *H5FD__mirror_fapl_get(H5FD_t *_file);
static void *H5FD__mirror_fapl_copy(const void *_old_fa);
static herr_t H5FD__mirror_fapl_free(void *_fa);
static haddr_t H5FD__mirror_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
static herr_t H5FD__mirror_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
static haddr_t H5FD__mirror_get_eof(const H5FD_t *_file, H5FD_mem_t type);
static H5FD_t *H5FD__mirror_open(const char *name, unsigned flags,
hid_t fapl_id, haddr_t maxaddr);
static herr_t H5FD__mirror_close(H5FD_t *_file);
static herr_t H5FD__mirror_query(const H5FD_t *_file, unsigned long *flags);
static herr_t H5FD__mirror_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id,
haddr_t addr, size_t size, const void *buf);
static herr_t H5FD__mirror_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id,
haddr_t addr, size_t size, void *buf);
static herr_t H5FD__mirror_truncate(H5FD_t *_file, hid_t dxpl_id,
hbool_t closing);
static herr_t H5FD__mirror_lock(H5FD_t *_file, hbool_t rw);
static herr_t H5FD__mirror_unlock(H5FD_t *_file);
static herr_t H5FD__mirror_verify_reply(H5FD_mirror_t *file);
static const H5FD_class_t H5FD_mirror_g = {
"mirror", /* name */
MAXADDR, /* maxaddr */
H5F_CLOSE_WEAK, /* fc_degree */
H5FD__mirror_term, /* terminate */
NULL, /* sb_size */
NULL, /* sb_encode */
NULL, /* sb_decode */
0, /* fapl_size */
H5FD__mirror_fapl_get, /* fapl_get */
H5FD__mirror_fapl_copy, /* fapl_copy */
H5FD__mirror_fapl_free, /* fapl_free */
0, /* dxpl_size */
NULL, /* dxpl_copy */
NULL, /* dxpl_free */
H5FD__mirror_open, /* open */
H5FD__mirror_close, /* close */
NULL, /* cmp */
H5FD__mirror_query, /* query */
NULL, /* get_type_map */
NULL, /* alloc */
NULL, /* free */
H5FD__mirror_get_eoa, /* get_eoa */
H5FD__mirror_set_eoa, /* set_eoa */
H5FD__mirror_get_eof, /* get_eof */
NULL, /* get_handle */
H5FD__mirror_read, /* read */
H5FD__mirror_write, /* write */
NULL, /* flush */
H5FD__mirror_truncate, /* truncate */
H5FD__mirror_lock, /* lock */
H5FD__mirror_unlock, /* unlock */
H5FD_FLMAP_DICHOTOMY /* fl_map */
};
/* Declare a free list to manage the transmission buffers */
H5FL_BLK_DEFINE_STATIC(xmit);
/* Declare a free list to manage the H5FD_mirror_t struct */
H5FL_DEFINE_STATIC(H5FD_mirror_t);
/* Declare a free list to manage the H5FD_mirror_xmit_open_t struct */
H5FL_DEFINE_STATIC(H5FD_mirror_xmit_open_t);
/*-------------------------------------------------------------------------
* Function: H5FD__init_package
*
* Purpose: Initializes any interface-specific data or routines.
*
* Return: Non-negative on success/Negative on failure
*-------------------------------------------------------------------------
*/
static herr_t
H5FD__init_package(void)
{
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
if(H5FD_mirror_init() < 0)
HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize mirror VFD");
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* H5FD__init_package() */
/* -------------------------------------------------------------------------
* Function: H5FD_mirror_init
*
* Purpose: Initialize this driver by registering the driver with the
* library.
*
* Return: Success: The driver ID for the mirror driver.
* Failure: Negative
* -------------------------------------------------------------------------
*/
hid_t
H5FD_mirror_init(void)
{
hid_t ret_value = H5I_INVALID_HID;
FUNC_ENTER_NOAPI(FAIL)
LOG_OP_CALL(FUNC);
if(H5I_VFL != H5I_get_type(H5FD_MIRROR_g))
H5FD_MIRROR_g = H5FD_register(&H5FD_mirror_g, sizeof(H5FD_class_t), FALSE);
ret_value = H5FD_MIRROR_g;
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_mirror_init() */
/* ---------------------------------------------------------------------------
* Function: H5FD__mirror_term
*
* Purpose: Shut down the VFD
*
* Returns: SUCCEED (Can't fail)
* ---------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_term(void)
{
FUNC_ENTER_STATIC_NOERR
/* Reset VFL ID */
H5FD_MIRROR_g = 0;
LOG_OP_CALL(FUNC);
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5FD__mirror_term() */
/* ---------------------------------------------------------------------------
* Function: H5FD__mirror_xmit_decode_uint16
*
* Purpose: Extract a 16-bit integer in "network" (Big-Endian) word order
* from the byte-buffer and return it with the local word order at
* the destination pointer.
*
* The programmer must ensure that the received buffer holds
* at least the expected size of data.
*
* Return: The number of bytes read from the buffer (2).
* ---------------------------------------------------------------------------
*/
size_t
H5FD__mirror_xmit_decode_uint16(uint16_t *out, const unsigned char *_buf)
{
uint16_t n = 0;
LOG_OP_CALL(__func__);
HDassert(_buf && out);
HDmemcpy(&n, _buf, sizeof(n));
*out = (uint16_t)HDntohs(n);
return 2; /* number of bytes eaten */
} /* end H5FD__mirror_xmit_decode_uint16() */
/* ---------------------------------------------------------------------------
* Function: H5FD__mirror_xmit_decode_uint32
*
* Purpose: Extract a 32-bit integer in "network" (Big-Endian) word order
* from the byte-buffer and return it with the local word order at
* the destination pointer.
*
* The programmer must ensure that the received buffer holds
* at least the expected size of data.
*
* Return: The number of bytes read from the buffer (4).
* ---------------------------------------------------------------------------
*/
size_t
H5FD__mirror_xmit_decode_uint32(uint32_t *out, const unsigned char *_buf)
{
uint32_t n = 0;
LOG_OP_CALL(__func__);
HDassert(_buf && out);
HDmemcpy(&n, _buf, sizeof(n));
*out = (uint32_t)HDntohl(n);
return 4; /* number of bytes eaten */
} /* end H5FD__mirror_xmit_decode_uint32() */
/* ---------------------------------------------------------------------------
* Function: is_host_little_endian
*
* Purpose: Determine whether the host machine is is little-endian.
*
* Store an intger with a known value, re-map the memory to a
* character array, and inspect the array's contents.
*
* Return: The number of bytes written to the buffer (8).
*
* Programmer: Jacob Smith
* 2020-03-05
* ---------------------------------------------------------------------------
*/
static hbool_t
is_host_little_endian(void)
{
union {
uint32_t u32;
uint8_t u8[4];
} echeck;
echeck.u32 = 0xA1B2C3D4;
if(echeck.u8[0] == 0xD4)
return TRUE;
else
return FALSE;
} /* end is_host_little_endian() */
/* ---------------------------------------------------------------------------
* Function: H5FD__mirror_xmit_decode_uint64
*
* Purpose: Extract a 64-bit integer in "network" (Big-Endian) word order
* from the byte-buffer and return it with the local word order.
*
* The programmer must ensure that the received buffer holds
* at least the expected size of data.
*
* WARNING: Does not accommodate other forms of endianness,
* e.g. "middle-endian".
*
* Return: The number of bytes written to the buffer (8).
* ---------------------------------------------------------------------------
*/
size_t
H5FD__mirror_xmit_decode_uint64(uint64_t *out, const unsigned char *_buf)
{
uint64_t n = 0;
LOG_OP_CALL(__func__);
HDassert(_buf && out);
HDmemcpy(&n, _buf, sizeof(n));
if(TRUE == is_host_little_endian())
*out = BSWAP_64(n);
else
*out = n;
return 8;
} /* end H5FD__mirror_xmit_decode_uint64() */
/* ---------------------------------------------------------------------------
* Function: H5FD__mirror_xmit_decode_uint8
*
* Purpose: Extract a 8-bit integer in "network" (Big-Endian) word order
* from the byte-buffer and return it with the local word order at
* the destination pointer.
* (yes, it's one byte).
*
* Return: The number of bytes read from the buffer (1).
* ---------------------------------------------------------------------------
*/
size_t
H5FD__mirror_xmit_decode_uint8(uint8_t *out, const unsigned char *_buf)
{
LOG_OP_CALL(__func__);
HDassert(_buf && out);
HDmemcpy(out, _buf, sizeof(uint8_t));
return 1; /* number of bytes eaten */
} /* end H5FD__mirror_xmit_decode_uint8() */
/* ---------------------------------------------------------------------------
* Function: H5FD__mirror_xmit_encode_uint16
*
* Purpose: Encode a 16-bit integer in "network" (Big-Endian) word order
* in place in the destination bytes-buffer.
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The number of bytes written to the buffer (2).
* ---------------------------------------------------------------------------
*/
size_t
H5FD__mirror_xmit_encode_uint16(unsigned char *_dest, uint16_t v)
{
uint16_t n = 0;
LOG_OP_CALL(__func__);
HDassert(_dest);
n = (uint16_t)HDhtons(v);
HDmemcpy(_dest, &n, sizeof(n));
return 2;
} /* end H5FD__mirror_xmit_encode_uint16() */
/* ---------------------------------------------------------------------------
* Function: H5FD__mirror_xmit_encode_uint32
*
* Purpose: Encode a 32-bit integer in "network" (Big-Endian) word order
* in place in the destination bytes-buffer.
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The number of bytes written to the buffer (4).
* ---------------------------------------------------------------------------
*/
size_t
H5FD__mirror_xmit_encode_uint32(unsigned char *_dest, uint32_t v)
{
uint32_t n = 0;
LOG_OP_CALL(__func__);
HDassert(_dest);
n = (uint32_t)HDhtonl(v);
HDmemcpy(_dest, &n, sizeof(n));
return 4;
} /* end H5FD__mirror_xmit_encode_uint32() */
/* ---------------------------------------------------------------------------
* Function: H5FD__mirror_xmit_encode_uint64
*
* Purpose: Encode a 64-bit integer in "network" (Big-Endian) word order
* in place in the destination bytes-buffer.
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The number of bytes written to the buffer (8).
* ---------------------------------------------------------------------------
*/
size_t
H5FD__mirror_xmit_encode_uint64(unsigned char *_dest, uint64_t v)
{
uint64_t n = v;
LOG_OP_CALL(__func__);
HDassert(_dest);
if(TRUE == is_host_little_endian())
n = BSWAP_64(v);
HDmemcpy(_dest, &n, sizeof(n));
return 8;
} /* H5FD__mirror_xmit_encode_uint64() */
/* ---------------------------------------------------------------------------
* Function: H5FD__mirror_xmit_encode_uint8
*
* Purpose: Encode a 8-bit integer in "network" (Big-Endian) word order
* in place in the destination bytes-buffer.
* (yes, it's one byte).
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The number of bytes read from the buffer (1).
* ---------------------------------------------------------------------------
*/
size_t
H5FD__mirror_xmit_encode_uint8(unsigned char *dest, uint8_t v)
{
LOG_OP_CALL(__func__);
HDassert(dest);
HDmemcpy(dest, &v, sizeof(v));
return 1;
} /* end H5FD__mirror_xmit_encode_uint8() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_decode_header
*
* Purpose: Extract a mirror_xmit_t "header" from the bytes-buffer.
*
* Fields will be lifted from the buffer and stored in the
* target structure, using in the correct location (different
* systems may insert different padding between components) and
* word order (Big- vs Little-Endian).
*
* The resulting structure should be sanity-checked with
* H5FD_mirror_xmit_is_xmit() before use.
*
* The programmer must ensure that the received buffer holds
* at least the expected size of data.
*
* Return: The number of bytes consumed from the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_decode_header(H5FD_mirror_xmit_t *out,
const unsigned char *buf)
{
size_t n_eaten = 0;
LOG_OP_CALL(__func__);
HDassert(out && buf);
n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->magic), &buf[n_eaten]);
n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->version), &buf[n_eaten]);
n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->session_token),
&buf[n_eaten]);
n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->xmit_count),
&buf[n_eaten]);
n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->op), &buf[n_eaten]);
HDassert(n_eaten == H5FD_MIRROR_XMIT_HEADER_SIZE);
return n_eaten;
} /* end H5FD_mirror_xmit_decode_header() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_decode_lock
*
* Purpose: Extract a mirror_xmit_lock_t from the bytes-buffer.
*
* Fields will be lifted from the buffer and stored in the
* target structure, using in the correct location (different
* systems may insert different padding between components) and
* word order (Big- vs Little-Endian).
*
* The programmer must ensure that the received buffer holds
* at least the expected size of data.
*
* The resulting structure should be sanity-checked with
* H5FD_mirror_xmit_is_lock() before use.
*
* Return: The number of bytes consumed from the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_decode_lock(H5FD_mirror_xmit_lock_t *out,
const unsigned char *buf)
{
size_t n_eaten = 0;
LOG_OP_CALL(__func__);
HDassert(out && buf);
n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->rw), &buf[n_eaten]);
HDassert(n_eaten == H5FD_MIRROR_XMIT_LOCK_SIZE);
return n_eaten;
} /* end H5FD_mirror_xmit_decode_lock() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_decode_open
*
* Purpose: Extract a mirror_xmit_open_t from the bytes-buffer.
*
* Fields will be lifted from the buffer and stored in the
* target structure, using in the correct location (different
* systems may insert different padding between components) and
* word order (Big- vs Little-Endian).
*
* The programmer must ensure that the received buffer holds
* at least the expected size of data.
*
* The resulting structure should be sanity-checked with
* H5FD_mirror_xmit_is_open() before use.
*
* Return: The maximum number of bytes that this decoding operation might
* have consumed from the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_decode_open(H5FD_mirror_xmit_open_t *out,
const unsigned char *buf)
{
size_t n_eaten = 0;
LOG_OP_CALL(__func__);
HDassert(out && buf);
n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->flags), &buf[n_eaten]);
n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->maxaddr), &buf[n_eaten]);
n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->size_t_blob),
&buf[n_eaten]);
HDassert((H5FD_MIRROR_XMIT_OPEN_SIZE - H5FD_MIRROR_XMIT_FILEPATH_MAX)
== n_eaten);
HDstrncpy(out->filename, (const char *)&buf[n_eaten],
H5FD_MIRROR_XMIT_FILEPATH_MAX - 1);
out->filename[H5FD_MIRROR_XMIT_FILEPATH_MAX - 1] = 0; /* force final NULL */
return H5FD_MIRROR_XMIT_OPEN_SIZE;
} /* end H5FD_mirror_xmit_decode_open() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_decode_reply
*
* Purpose: Extract a mirror_xmit_reply_t from the bytes-buffer.
*
* Fields will be lifted from the buffer and stored in the
* target structure, using in the correct location (different
* systems may insert different padding between components) and
* word order (Big- vs Little-Endian).
*
* The programmer must ensure that the received buffer holds
* at least the expected size of data.
*
* The resulting structure should be sanity-checked with
* H5FD_mirror_xmit_is_reply() before use.
*
* Return: The maximum number of bytes that this decoding operation might
* have consumed from the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_decode_reply(H5FD_mirror_xmit_reply_t *out,
const unsigned char *buf)
{
size_t n_eaten = 0;
LOG_OP_CALL(__func__);
HDassert(out && buf);
n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->status), &buf[n_eaten]);
HDassert((H5FD_MIRROR_XMIT_REPLY_SIZE - H5FD_MIRROR_STATUS_MESSAGE_MAX)
== n_eaten);
HDstrncpy(out->message, (const char *)&buf[n_eaten],
H5FD_MIRROR_STATUS_MESSAGE_MAX - 1);
out->message[H5FD_MIRROR_STATUS_MESSAGE_MAX - 1] = 0; /* force NULL term */
return H5FD_MIRROR_XMIT_REPLY_SIZE;
} /* end H5FD_mirror_xmit_decode_reply() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_decode_set_eoa
*
* Purpose: Extract a mirror_xmit_eoa_t from the bytes-buffer.
*
* Fields will be lifted from the buffer and stored in the
* target structure, using in the correct location (different
* systems may insert different padding between components) and
* word order (Big- vs Little-Endian).
*
* The programmer must ensure that the received buffer holds
* at least the expected size of data.
*
* The resulting structure should be sanity-checked with
* H5FD_mirror_xmit_is_set_eoa() before use.
*
* Return: The number of bytes consumed from the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_decode_set_eoa(H5FD_mirror_xmit_eoa_t *out,
const unsigned char *buf)
{
size_t n_eaten = 0;
LOG_OP_CALL(__func__);
HDassert(out && buf);
n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->type), &buf[n_eaten]);
n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->eoa_addr), &buf[n_eaten]);
HDassert(n_eaten == H5FD_MIRROR_XMIT_EOA_SIZE);
return n_eaten;
} /* end H5FD_mirror_xmit_decode_set_eoa() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_decode_write
*
* Purpose: Extract a mirror_xmit_write_t from the bytes-buffer.
*
* Fields will be lifted from the buffer and stored in the
* target structure, using in the correct location (different
* systems may insert different padding between components) and
* word order (Big- vs Little-Endian).
*
* The programmer must ensure that the received buffer holds
* at least the expected size of data.
*
* The resulting structure should be sanity-checked with
* H5FD_mirror_xmit_is_write() before use.
*
* Return: The number of bytes consumed from the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_decode_write(H5FD_mirror_xmit_write_t *out,
const unsigned char *buf)
{
size_t n_eaten = 0;
LOG_OP_CALL(__func__);
HDassert(out && buf);
n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->type), &buf[n_eaten]);
n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->offset), &buf[n_eaten]);
n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->size), &buf[n_eaten]);
HDassert(n_eaten == H5FD_MIRROR_XMIT_WRITE_SIZE);
return n_eaten;
} /* end H5FD_mirror_xmit_decode_write() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_encode_header
*
* Purpose: Encode a mirror_xmit_t "header" to the bytes-buffer.
*
* Fields will be packed into the buffer in a predictable manner,
* any numbers stored in "network" (Big-Endian) word order.
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The number of bytes written to the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_encode_header(unsigned char *dest,
const H5FD_mirror_xmit_t *x)
{
size_t n_writ = 0;
LOG_OP_CALL(__func__);
HDassert(dest && x);
n_writ += H5FD__mirror_xmit_encode_uint32((dest+n_writ), x->magic);
n_writ += H5FD__mirror_xmit_encode_uint8((dest+n_writ), x->version);
n_writ += H5FD__mirror_xmit_encode_uint32((dest+n_writ), x->session_token);
n_writ += H5FD__mirror_xmit_encode_uint32((dest+n_writ), x->xmit_count);
n_writ += H5FD__mirror_xmit_encode_uint8((dest+n_writ), x->op);
HDassert(n_writ == H5FD_MIRROR_XMIT_HEADER_SIZE);
return n_writ;
} /* end H5FD_mirror_xmit_encode_header() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_encode_lock
*
* Purpose: Encode a mirror_xmit_lock_t to the bytes-buffer.
* Fields will be packed into the buffer in a predictable manner,
* any numbers stored in "network" (Big-Endian) word order.
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The number of bytes written to the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_encode_lock(unsigned char *dest,
const H5FD_mirror_xmit_lock_t *x)
{
size_t n_writ = 0;
LOG_OP_CALL(__func__);
HDassert(dest && x);
n_writ += H5FD_mirror_xmit_encode_header(dest,
(const H5FD_mirror_xmit_t *)&(x->pub));
n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->rw);
HDassert(n_writ == H5FD_MIRROR_XMIT_LOCK_SIZE);
return n_writ;
} /* end H5FD_mirror_xmit_encode_lock() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_encode_open
*
* Purpose: Encode a mirror_xmit_open_t to the bytes-buffer.
* Fields will be packed into the buffer in a predictable manner,
* any numbers stored in "network" (Big-Endian) word order.
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The maximum number of bytes that this decoding operation might
* have written into the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_encode_open(unsigned char *dest,
const H5FD_mirror_xmit_open_t *x)
{
size_t n_writ = 0;
LOG_OP_CALL(__func__);
HDassert(dest && x);
/* clear entire structure, but especially its filepath string area */
HDmemset(dest, 0, H5FD_MIRROR_XMIT_OPEN_SIZE);
n_writ += H5FD_mirror_xmit_encode_header(dest,
(const H5FD_mirror_xmit_t *)&(x->pub));
n_writ += H5FD__mirror_xmit_encode_uint32(&dest[n_writ], x->flags);
n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->maxaddr);
n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->size_t_blob);
HDassert((H5FD_MIRROR_XMIT_OPEN_SIZE - H5FD_MIRROR_XMIT_FILEPATH_MAX)
== n_writ);
HDstrncpy((char *)&dest[n_writ], x->filename, H5FD_MIRROR_XMIT_FILEPATH_MAX);
return H5FD_MIRROR_XMIT_OPEN_SIZE;
} /* end H5FD_mirror_xmit_encode_open() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_encode_reply
*
* Purpose: Encode a mirror_xmit_reply_t to the bytes-buffer.
*
* Fields will be packed into the buffer in a predictable manner,
* any numbers stored in "network" (Big-Endian) word order.
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The maximum number of bytes that this decoding operation might
* have written into the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_encode_reply(unsigned char *dest,
const H5FD_mirror_xmit_reply_t *x)
{
size_t n_writ = 0;
LOG_OP_CALL(__func__);
HDassert(dest && x);
/* clear entire structure, but especially its message string area */
HDmemset(dest, 0, H5FD_MIRROR_XMIT_REPLY_SIZE);
n_writ += H5FD_mirror_xmit_encode_header(dest,
(const H5FD_mirror_xmit_t *)&(x->pub));
n_writ += H5FD__mirror_xmit_encode_uint32(&dest[n_writ], x->status);
HDassert((H5FD_MIRROR_XMIT_REPLY_SIZE - H5FD_MIRROR_STATUS_MESSAGE_MAX)
== n_writ);
HDstrncpy((char *)&dest[n_writ], x->message, H5FD_MIRROR_STATUS_MESSAGE_MAX);
return H5FD_MIRROR_XMIT_REPLY_SIZE;
} /* end H5FD_mirror_xmit_encode_reply() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_encode_set_eoa
*
* Purpose: Encode a mirror_xmit_eoa_t to the bytes-buffer.
*
* Fields will be packed into the buffer in a predictable manner,
* any numbers stored in "network" (Big-Endian) word order.
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The number of bytes written to the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_encode_set_eoa(unsigned char *dest,
const H5FD_mirror_xmit_eoa_t *x)
{
size_t n_writ = 0;
LOG_OP_CALL(__func__);
HDassert(dest && x);
n_writ += H5FD_mirror_xmit_encode_header(dest,
(const H5FD_mirror_xmit_t *)&(x->pub));
n_writ += H5FD__mirror_xmit_encode_uint8(&dest[n_writ], x->type);
n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->eoa_addr);
HDassert(n_writ == H5FD_MIRROR_XMIT_EOA_SIZE);
return n_writ;
} /* end H5FD_mirror_xmit_encode_set_eoa() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_encode_write
*
* Purpose: Encode a mirror_xmit_write_t to the bytes-buffer.
*
* Fields will be packed into the buffer in a predictable manner,
* any numbers stored in "network" (Big-Endian) word order.
*
* The programmer must ensure that the destination buffer is
* large enough to hold the expected data.
*
* Return: The number of bytes written to the buffer.
* ---------------------------------------------------------------------------
*/
size_t
H5FD_mirror_xmit_encode_write(unsigned char *dest,
const H5FD_mirror_xmit_write_t *x)
{
size_t n_writ = 0;
LOG_OP_CALL(__func__);
HDassert(dest && x);
n_writ += H5FD_mirror_xmit_encode_header(dest,
(const H5FD_mirror_xmit_t *)&(x->pub));
n_writ += H5FD__mirror_xmit_encode_uint8(&dest[n_writ], x->type);
n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->offset);
n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->size);
HDassert(n_writ == H5FD_MIRROR_XMIT_WRITE_SIZE);
return n_writ;
} /* end H5FD_mirror_xmit_encode_write() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_is_close
*
* Purpose: Verify that a mirror_xmit_t is a valid CLOSE xmit.
*
* Checks header validity and op code.
*
* Return: TRUE if valid; else FALSE.
* ---------------------------------------------------------------------------
*/
H5_ATTR_PURE hbool_t
H5FD_mirror_xmit_is_close(const H5FD_mirror_xmit_t *xmit)
{
LOG_OP_CALL(__func__);
HDassert(xmit);
if((TRUE == H5FD_mirror_xmit_is_xmit(xmit)) && (H5FD_MIRROR_OP_CLOSE == xmit->op))
return TRUE;
return FALSE;
} /* end H5FD_mirror_xmit_is_close() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_is_lock
*
* Purpose: Verify that a mirror_xmit_lock_t is a valid LOCK xmit.
*
* Checks header validity and op code.
*
* Return: TRUE if valid; else FALSE.
* ---------------------------------------------------------------------------
*/
H5_ATTR_PURE hbool_t
H5FD_mirror_xmit_is_lock(const H5FD_mirror_xmit_lock_t *xmit)
{
LOG_OP_CALL(__func__);
HDassert(xmit);
if((TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && (H5FD_MIRROR_OP_LOCK == xmit->pub.op))
return TRUE;
return FALSE;
} /* end H5FD_mirror_xmit_is_lock() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_is_open
*
* Purpose: Verify that a mirror_xmit_open_t is a valid OPEN xmit.
*
* Checks header validity and op code.
*
* Return: TRUE if valid; else FALSE.
* ---------------------------------------------------------------------------
*/
H5_ATTR_PURE hbool_t
H5FD_mirror_xmit_is_open(const H5FD_mirror_xmit_open_t *xmit)
{
LOG_OP_CALL(__func__);
HDassert(xmit);
if((TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && (H5FD_MIRROR_OP_OPEN == xmit->pub.op))
return TRUE;
return FALSE;
} /* end H5FD_mirror_xmit_is_open() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_is_eoa
*
* Purpose: Verify that a mirror_xmit_eoa_t is a valid SET-EOA xmit.
*
* Checks header validity and op code.
*
* Return: TRUE if valid; else FALSE.
* ---------------------------------------------------------------------------
*/
H5_ATTR_PURE hbool_t
H5FD_mirror_xmit_is_set_eoa(const H5FD_mirror_xmit_eoa_t *xmit)
{
LOG_OP_CALL(__func__);
HDassert(xmit);
if((TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && (H5FD_MIRROR_OP_SET_EOA == xmit->pub.op))
return TRUE;
return FALSE;
} /* end H5FD_mirror_xmit_is_eoa() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_is_reply
*
* Purpose: Verify that a mirror_xmit_reply_t is a valid REPLY xmit.
*
* Checks header validity and op code.
*
* Return: TRUE if valid; else FALSE.
* ---------------------------------------------------------------------------
*/
H5_ATTR_PURE hbool_t
H5FD_mirror_xmit_is_reply(const H5FD_mirror_xmit_reply_t *xmit)
{
LOG_OP_CALL(__func__);
HDassert(xmit);
if((TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && (H5FD_MIRROR_OP_REPLY == xmit->pub.op))
return TRUE;
return FALSE;
} /* end H5FD_mirror_xmit_is_reply() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_is_write
*
* Purpose: Verify that a mirror_xmit_write_t is a valid WRITE xmit.
*
* Checks header validity and op code.
*
* Return: TRUE if valid; else FALSE.
* ---------------------------------------------------------------------------
*/
H5_ATTR_PURE hbool_t
H5FD_mirror_xmit_is_write(const H5FD_mirror_xmit_write_t *xmit)
{
LOG_OP_CALL(__func__);
HDassert(xmit);
if((TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && (H5FD_MIRROR_OP_WRITE == xmit->pub.op))
return TRUE;
return FALSE;
} /* end H5FD_mirror_xmit_is_write() */
/* ---------------------------------------------------------------------------
* Function: H5FD_mirror_xmit_is_xmit
*
* Purpose: Verify that a mirror_xmit_t is well-formed.
*
* Checks magic number and structure version.
*
* Return: TRUE if valid; else FALSE.
* ---------------------------------------------------------------------------
*/
H5_ATTR_PURE hbool_t
H5FD_mirror_xmit_is_xmit(const H5FD_mirror_xmit_t *xmit)
{
LOG_OP_CALL(__func__);
HDassert(xmit);
if((H5FD_MIRROR_XMIT_MAGIC != xmit->magic) || (H5FD_MIRROR_XMIT_CURR_VERSION != xmit->version))
return FALSE;
return TRUE;
} /* end H5FD_mirror_xmit_is_xmit() */
/* ----------------------------------------------------------------------------
* Function: H5FD__mirror_verify_reply
*
* Purpose: Wait for and read reply data from remote processes.
* Sanity-check that a reply is well-formed and valid.
* If all checks pass, inspect the reply contents and handle
* reported error, if not an OK reply.
*
* Return: SUCCEED if ok, else FAIL.
* ----------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_verify_reply(H5FD_mirror_t *file)
{
unsigned char *xmit_buf = NULL;
struct H5FD_mirror_xmit_reply_t reply;
ssize_t read_ret = 0;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
HDassert(file && file->sock_fd);
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
if(NULL == xmit_buf)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
read_ret = HDread(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_REPLY_SIZE);
if(read_ret < 0)
HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "unable to read reply");
if(read_ret != H5FD_MIRROR_XMIT_REPLY_SIZE)
HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "unexpected read size");
LOG_XMIT_BYTES("reply", xmit_buf, read_ret);
if(H5FD_mirror_xmit_decode_reply(&reply, xmit_buf) != H5FD_MIRROR_XMIT_REPLY_SIZE)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unable to decode reply xmit");
if(H5FD_mirror_xmit_is_reply(&reply) != TRUE)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "xmit op code was not REPLY");
if(reply.pub.session_token != file->xmit.session_token)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "wrong session");
if(reply.pub.xmit_count != (file->xmit_i)++)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "xmit out of sync");
if(reply.status != H5FD_MIRROR_STATUS_OK)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "%s", (const char *)(reply.message));
done:
if(xmit_buf)
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
FUNC_LEAVE_NOAPI(ret_value);
} /* end H5FD__mirror_verify_reply() */
/* -------------------------------------------------------------------------
* Function: H5FD__mirror_fapl_get
*
* Purpose: Get the file access propety list which could be used to create
* an identical file.
*
* Return: Success: pointer to the new file access property list value.
* Failure: NULL
* -------------------------------------------------------------------------
*/
static void *
H5FD__mirror_fapl_get(H5FD_t *_file)
{
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
H5FD_mirror_fapl_t *fa = NULL;
void *ret_value = NULL;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
fa = (H5FD_mirror_fapl_t *)H5MM_calloc(sizeof(H5FD_mirror_fapl_t));
if(NULL == fa)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "calloc failed");
HDmemcpy(fa, &(file->fa), sizeof(H5FD_mirror_fapl_t));
ret_value = fa;
done:
if(ret_value == NULL)
if(fa != NULL)
H5MM_xfree(fa);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD__mirror_fapl_get() */
/* -------------------------------------------------------------------------
* Function: H5FD__mirror_fapl_copy
*
* Purpose: Copies the mirror vfd-specific file access properties.
*
* Return: Success: Pointer to a new property list
* Failure: NULL
* -------------------------------------------------------------------------
*/
static void *
H5FD__mirror_fapl_copy(const void *_old_fa)
{
const H5FD_mirror_fapl_t *old_fa = (const H5FD_mirror_fapl_t *)_old_fa;
H5FD_mirror_fapl_t *new_fa = NULL;
void *ret_value = NULL;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
new_fa = (H5FD_mirror_fapl_t *)H5MM_malloc(sizeof(H5FD_mirror_fapl_t));
if(new_fa == NULL)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "memory allocation failed");
HDmemcpy(new_fa, old_fa, sizeof(H5FD_mirror_fapl_t));
ret_value = new_fa;
done:
if(ret_value == NULL)
if(new_fa != NULL)
H5MM_xfree(new_fa);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD__mirror_fapl_copy() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_fapl_free
*
* Purpose: Frees the mirror VFD-specific file access properties.
*
* Return: SUCCEED (cannot fail)
*-------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_fapl_free(void *_fa)
{
H5FD_mirror_fapl_t *fa = (H5FD_mirror_fapl_t*)_fa;
FUNC_ENTER_STATIC_NOERR
LOG_OP_CALL(FUNC);
/* sanity check */
HDassert(fa != NULL);
HDassert(fa->magic == H5FD_MIRROR_FAPL_MAGIC);
fa->magic += 1; /* invalidate */
H5MM_xfree(fa);
FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5FD__mirror_fapl_free() */
/* -------------------------------------------------------------------------
* Function: H5Pget_fapl_mirror
*
* Purpose: Get the configuration information for this fapl.
* Data is memcopied into the fa_out pointer.
*
* Return: SUCCEED/FAIL
* -------------------------------------------------------------------------
*/
herr_t
H5Pget_fapl_mirror(hid_t fapl_id, H5FD_mirror_fapl_t *fa_out)
{
const H5FD_mirror_fapl_t *fa = NULL;
H5P_genplist_t *plist = NULL;
herr_t ret_value = SUCCEED;
FUNC_ENTER_API(FAIL)
H5TRACE2("e", "i*x", fapl_id, fa_out);
LOG_OP_CALL(FUNC);
if(NULL == fa_out)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "fa_out is NULL");
plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS);
if(NULL == plist)
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
if(H5P_peek_driver(plist) != H5FD_MIRROR)
HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver");
fa = (const H5FD_mirror_fapl_t *)H5P_peek_driver_info(plist);
if(NULL == fa)
HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info");
HDassert(fa->magic == H5FD_MIRROR_FAPL_MAGIC); /* sanity check */
HDmemcpy(fa_out, fa, sizeof(H5FD_mirror_fapl_t));
done:
FUNC_LEAVE_API(ret_value);
} /* end H5Pget_fapl_mirror() */
/*-------------------------------------------------------------------------
* Function: H5Pset_fapl_mirror
*
* Purpose: Modify the file access property list to use the mirror
* driver (H5FD_MIRROR) defined in this source file.
*
* Return: SUCCEED/FAIL
*-------------------------------------------------------------------------
*/
herr_t
H5Pset_fapl_mirror(hid_t fapl_id, H5FD_mirror_fapl_t *fa)
{
H5P_genplist_t *plist = NULL;
herr_t ret_value = FAIL;
FUNC_ENTER_API(FAIL)
H5TRACE2("e", "i*x", fapl_id, fa);
LOG_OP_CALL(FUNC);
plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS);
if(NULL == plist)
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
if(NULL == fa)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null fapl_t pointer");
if(H5FD_MIRROR_FAPL_MAGIC != fa->magic)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid fapl_t magic");
if(H5FD_MIRROR_CURR_FAPL_T_VERSION != fa->version)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown fapl_t version");
ret_value = H5P_set_driver(plist, H5FD_MIRROR, (const void *)fa);
done:
FUNC_LEAVE_API(ret_value)
} /* end H5Pset_fapl_mirror() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_open
*
* Purpose: Create and/or opens a file as an HDF5 file.
*
* Initiate connection with remote Server/Writer.
* If successful, the remote file is open.
*
* 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__mirror_open(const char *name,
unsigned flags,
hid_t fapl_id,
haddr_t maxaddr)
{
int live_socket = -1;
struct sockaddr_in target_addr;
socklen_t addr_size;
unsigned char *xmit_buf = NULL;
H5FD_mirror_fapl_t fa;
H5FD_mirror_t *file = NULL;
H5FD_mirror_xmit_open_t *open_xmit = NULL;
H5FD_t *ret_value = NULL;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
/* --------------- */
/* Check arguments */
/* --------------- */
if(!name || !*name)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name");
if(HDstrlen(name) >= H5FD_MIRROR_XMIT_FILEPATH_MAX)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "filename is too long");
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(H5Pget_fapl_mirror(fapl_id, &fa) == FAIL)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "can't get config info");
if(H5FD_MIRROR_FAPL_MAGIC != fa.magic)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid fapl magic");
if(H5FD_MIRROR_CURR_FAPL_T_VERSION != fa.version)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid fapl version");
/* --------------------- */
/* Handshake with remote */
/* --------------------- */
live_socket = HDsocket(AF_INET, SOCK_STREAM, 0);
if(live_socket < 0)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "can't create socket");
target_addr.sin_family = AF_INET;
target_addr.sin_port = HDhtons((uint16_t)fa.handshake_port);
target_addr.sin_addr.s_addr = HDinet_addr(fa.remote_ip);
HDmemset(target_addr.sin_zero, '\0', sizeof target_addr.sin_zero);
addr_size = sizeof(target_addr);
if(HDconnect(live_socket, (struct sockaddr *)&target_addr, addr_size) < 0)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "can't connect to remote server");
/* ------------- */
/* Open the file */
/* ------------- */
file = (H5FD_mirror_t *)H5FL_CALLOC(H5FD_mirror_t);
if(NULL == file)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate file struct");
file->sock_fd = live_socket;
file->xmit_i = 0;
file->xmit.magic = H5FD_MIRROR_XMIT_MAGIC;
file->xmit.version = H5FD_MIRROR_XMIT_CURR_VERSION;
file->xmit.xmit_count = file->xmit_i++;
file->xmit.session_token = (uint32_t)(0x01020304 ^ file->sock_fd); /* TODO: hashing? */
/* int --> uint32_t may truncate on some systems... shouldn't matter? */
open_xmit = (H5FD_mirror_xmit_open_t *)H5FL_CALLOC(H5FD_mirror_xmit_open_t);
if(NULL == open_xmit)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate open_xmit struct");
file->xmit.op = H5FD_MIRROR_OP_OPEN;
open_xmit->pub = file->xmit;
open_xmit->flags = (uint32_t)flags;
open_xmit->maxaddr = (uint64_t)maxaddr;
open_xmit->size_t_blob = (uint64_t)((size_t)(-1));
HDsnprintf(open_xmit->filename, H5FD_MIRROR_XMIT_FILEPATH_MAX-1, "%s", name);
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
if(NULL == xmit_buf)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate xmit buffer");
if(H5FD_mirror_xmit_encode_open(xmit_buf, open_xmit) != H5FD_MIRROR_XMIT_OPEN_SIZE)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, NULL, "unable to encode open");
LOG_XMIT_BYTES("open", xmit_buf, H5FD_MIRROR_XMIT_OPEN_SIZE);
if(HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_OPEN_SIZE) < 0)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, NULL, "unable to transmit open");
if(H5FD__mirror_verify_reply(file) == FAIL)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "invalid reply");
ret_value = (H5FD_t *)file;
done:
if(NULL == ret_value) {
if(file)
file = H5FL_FREE(H5FD_mirror_t, file);
if(live_socket >= 0 && HDclose(live_socket) < 0)
HDONE_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, NULL, "can't close socket");
}
if(open_xmit)
open_xmit = H5FL_FREE(H5FD_mirror_xmit_open_t, open_xmit);
if(xmit_buf)
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD__mirror_open() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_close
*
* Purpose: Closes the HDF5 file.
*
* Tries to send a CLOSE op to the remote Writer and expects
* a valid reply, then closes the socket.
* In error, attempts to send a deliberately invalid xmit to the
* Writer to get it to close/abort, then attempts to close the
* socket.
*
* Return: Success: SUCCEED
* Failure: FAIL, file possibly not closed but resources freed.
*-------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_close(H5FD_t *_file)
{
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
unsigned char *xmit_buf = NULL;
int xmit_encoded = 0; /* monitor point of failure */
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
/* Sanity check */
HDassert(file);
HDassert(file->sock_fd >= 0);
file->xmit.xmit_count = (file->xmit_i)++;
file->xmit.op = H5FD_MIRROR_OP_CLOSE;
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
if(NULL == xmit_buf)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
if(H5FD_mirror_xmit_encode_header(xmit_buf, &(file->xmit)) != H5FD_MIRROR_XMIT_HEADER_SIZE)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to encode close");
xmit_encoded = 1;
LOG_XMIT_BYTES("close", xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE);
if(HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE) < 0)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to transmit close");
if(H5FD__mirror_verify_reply(file) == FAIL)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
if(HDclose(file->sock_fd) < 0)
HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "can't close socket");
done:
if(ret_value == FAIL) {
if(xmit_encoded == 0) {
/* Encode failed; send GOODBYE to force writer halt.
* We can ignore any response from the writer, if we receive
* any reply at all.
*/
if(HDwrite(file->sock_fd, "GOODBYE", HDstrlen("GOODBYE")) < 0) {
HDONE_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to transmit close");
if(HDclose(file->sock_fd) < 0)
HDONE_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "can't close socket");
file->sock_fd = -1; /* invalidate for later */
} /* end if problem writing goodbye; go down hard */
else
if(HDshutdown(file->sock_fd, SHUT_WR) < 0)
HDONE_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't shutdown socket write: %s", HDstrerror(errno));
} /* end if xmit encode failed */
if(file->sock_fd >= 0)
if(HDclose(file->sock_fd) < 0)
HDONE_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "can't close socket");
} /* end if error */
file = H5FL_FREE(H5FD_mirror_t, file); /* always release resources */
if(xmit_buf)
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD__mirror_close() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_query
*
* Purpose: Get the driver feature flags implemented by the driver.
*
* Return: SUCCEED (non-negative) (can't fail)
*-------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_query(const H5FD_t H5_ATTR_UNUSED *_file, unsigned long *flags)
{
FUNC_ENTER_STATIC_NOERR;
LOG_OP_CALL(FUNC);
/* Notice: the Mirror VFD Writer currently uses only the Sec2 driver as
* the underying driver -- as such, the Mirror VFD implementation copies
* the Sec2 feature flags as its own.
*
* File pointer is always NULL/unused -- the H5FD_FEAT_IGNORE_DRVRINFO flag
* is never included.
* -- JOS 2020-01-13
*/
if(flags)
*flags = H5FD_FEAT_AGGREGATE_METADATA \
| H5FD_FEAT_ACCUMULATE_METADATA \
| H5FD_FEAT_DATA_SIEVE \
| H5FD_FEAT_AGGREGATE_SMALLDATA \
| H5FD_FEAT_POSIX_COMPAT_HANDLE \
| H5FD_FEAT_SUPPORTS_SWMR_IO \
| H5FD_FEAT_DEFAULT_VFD_COMPATIBLE;
FUNC_LEAVE_NOAPI(SUCCEED);
} /* end H5FD__mirror_query() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_get_eoa
*
* Purpose: Gets 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.
*
* Required to register the driver.
*
* Return: The end-of-address marker.
*-------------------------------------------------------------------------
*/
static haddr_t
H5FD__mirror_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
{
const H5FD_mirror_t *file = (const H5FD_mirror_t *)_file;
FUNC_ENTER_STATIC_NOERR
LOG_OP_CALL(FUNC);
HDassert(file);
FUNC_LEAVE_NOAPI(file->eoa)
} /* end H5FD__mirror_get_eoa() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_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__mirror_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr)
{
H5FD_mirror_xmit_eoa_t xmit_eoa;
unsigned char *xmit_buf = NULL;
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
HDassert(file);
file->eoa = addr; /* local copy */
file->xmit.xmit_count = (file->xmit_i)++;
file->xmit.op = H5FD_MIRROR_OP_SET_EOA;
xmit_eoa.pub = file->xmit;
xmit_eoa.type = (uint8_t)type;
xmit_eoa.eoa_addr = (uint64_t)addr;
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
if(NULL == xmit_buf)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
if(H5FD_mirror_xmit_encode_set_eoa(xmit_buf, &xmit_eoa) != H5FD_MIRROR_XMIT_EOA_SIZE)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode set-eoa");
LOG_XMIT_BYTES("set-eoa", xmit_buf, H5FD_MIRROR_XMIT_EOA_SIZE);
if(HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_EOA_SIZE) < 0)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit set-eoa");
if(H5FD__mirror_verify_reply(file) == FAIL)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
done:
if(xmit_buf)
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD__mirror_set_eoa() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_get_eof
*
* Purpose: Returns the end-of-file marker, which is the greater of
* either the filesystem end-of-file or the HDF5 end-of-address
* markers.
*
* Required to register the driver.
*
* Return: End of file address, the first address past the end of the
* "file", either the filesystem file or the HDF5 file.
*-------------------------------------------------------------------------
*/
static haddr_t
H5FD__mirror_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
{
const H5FD_mirror_t *file = (const H5FD_mirror_t *)_file;
FUNC_ENTER_STATIC_NOERR
LOG_OP_CALL(FUNC);
HDassert(file);
FUNC_LEAVE_NOAPI(file->eof)
} /* end H5FD__mirror_get_eof() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_read
*
* Purpose: Required to register the driver, but if called, MUST fail.
*
* Return: FAIL
*-------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_read(H5FD_t H5_ATTR_UNUSED *_file, H5FD_mem_t H5_ATTR_UNUSED type,
hid_t H5_ATTR_UNUSED fapl_id, haddr_t H5_ATTR_UNUSED addr,
size_t H5_ATTR_UNUSED size, void H5_ATTR_UNUSED *buf)
{
FUNC_ENTER_STATIC_NOERR
LOG_OP_CALL(FUNC);
FUNC_LEAVE_NOAPI(FAIL)
} /* end H5FD__mirror_read() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_write
*
* Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
* from buffer BUF according to data transfer properties in
* DXPL_ID.
*
* Send metadata regarding the write (location, size) to the
* remote Writer, then separately transmits the data.
* Both transmission expect an OK reply from the Writer.
* This two-exchange approach incurs significant overhead,
* but is a simple and modular approach.
* Start optimizations here.
*
* Return: SUCCEED/FAIL
*-------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id,
haddr_t addr, size_t size, const void *buf)
{
H5FD_mirror_xmit_write_t xmit_write;
unsigned char *xmit_buf = NULL;
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
HDassert(file);
HDassert(buf);
file->xmit.xmit_count = (file->xmit_i)++;
file->xmit.op = H5FD_MIRROR_OP_WRITE;
xmit_write.pub = file->xmit;
xmit_write.size = (uint64_t)size;
xmit_write.offset = (uint64_t)addr;
xmit_write.type = (uint8_t)type;
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
if(NULL == xmit_buf)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
/* Notify Writer of incoming data to write. */
if(H5FD_mirror_xmit_encode_write(xmit_buf, &xmit_write) != H5FD_MIRROR_XMIT_WRITE_SIZE)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode write");
LOG_XMIT_BYTES("write", xmit_buf, H5FD_MIRROR_XMIT_WRITE_SIZE);
if(HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_WRITE_SIZE) < 0)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit write");
/* Check that our write xmission was received */
if(H5FD__mirror_verify_reply(file) == FAIL)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
/* Send the data to be written */
if(HDwrite(file->sock_fd, buf, size) < 0)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit data");
/* Writer should reply that it got the data and is still okay/ready */
if(H5FD__mirror_verify_reply(file) == FAIL)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
done:
if(xmit_buf)
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD__mirror_write() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_truncate
*
* Purpose: Makes sure that the true file size is the same (or larger)
* than the end-of-address.
*
* Return: SUCCEED/FAIL
*-------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id,
hbool_t H5_ATTR_UNUSED closing)
{
unsigned char *xmit_buf = NULL;
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
file->xmit.xmit_count = (file->xmit_i)++;
file->xmit.op = H5FD_MIRROR_OP_TRUNCATE;
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
if(NULL == xmit_buf)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
if(H5FD_mirror_xmit_encode_header(xmit_buf, &(file->xmit)) != H5FD_MIRROR_XMIT_HEADER_SIZE)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode truncate");
LOG_XMIT_BYTES("truncate", xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE);
if(HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE) < 0)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit truncate");
if(H5FD__mirror_verify_reply(file) == FAIL)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
done:
if(xmit_buf)
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD__mirror_truncate() */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_lock
*
* Purpose: To place an advisory lock on a file.
* The lock type to apply depends on the parameter "rw":
* TRUE--opens for write: an exclusive lock
* FALSE--opens for read: a shared lock
*
* Return: SUCCEED/FAIL
*-------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_lock(H5FD_t *_file, hbool_t rw)
{
H5FD_mirror_xmit_lock_t xmit_lock;
unsigned char *xmit_buf = NULL;
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
file->xmit.xmit_count = (file->xmit_i)++;
file->xmit.op = H5FD_MIRROR_OP_LOCK;
xmit_lock.pub = file->xmit;
xmit_lock.rw = (uint64_t)rw;
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
if(NULL == xmit_buf)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
if(H5FD_mirror_xmit_encode_lock(xmit_buf, &xmit_lock) != H5FD_MIRROR_XMIT_LOCK_SIZE)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode lock");
LOG_XMIT_BYTES("lock", xmit_buf, H5FD_MIRROR_XMIT_LOCK_SIZE);
if(HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_LOCK_SIZE) < 0)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit lock");
if(H5FD__mirror_verify_reply(file) == FAIL)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
done:
if(xmit_buf)
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
FUNC_LEAVE_NOAPI(ret_value);
} /* end H5FD__mirror_lock */
/*-------------------------------------------------------------------------
* Function: H5FD__mirror_unlock
*
* Purpose: Remove the existing lock on the file.
*
* Return: SUCCEED/FAIL
*-------------------------------------------------------------------------
*/
static herr_t
H5FD__mirror_unlock(H5FD_t *_file)
{
unsigned char *xmit_buf = NULL;
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
LOG_OP_CALL(FUNC);
file->xmit.xmit_count = (file->xmit_i)++;
file->xmit.op = H5FD_MIRROR_OP_UNLOCK;
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
if(NULL == xmit_buf)
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
if(H5FD_mirror_xmit_encode_header(xmit_buf, &(file->xmit)) != H5FD_MIRROR_XMIT_HEADER_SIZE)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode unlock");
LOG_XMIT_BYTES("unlock", xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE);
if(HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE) < 0)
HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit unlock");
if(H5FD__mirror_verify_reply(file) == FAIL)
HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
done:
if(xmit_buf)
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
FUNC_LEAVE_NOAPI(ret_value);
} /* end H5FD__mirror_unlock */
#endif /* H5_HAVE_MIRROR_VFD */