summaryrefslogtreecommitdiffstats
path: root/src/H5VLiod_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5VLiod_common.c')
-rw-r--r--src/H5VLiod_common.c1016
1 files changed, 1016 insertions, 0 deletions
diff --git a/src/H5VLiod_common.c b/src/H5VLiod_common.c
new file mode 100644
index 0000000..afb6089
--- /dev/null
+++ b/src/H5VLiod_common.c
@@ -0,0 +1,1016 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of h5netvol. The full h5netvol copyright notice, *
+ * including terms governing use, modification, and redistribution, is *
+ * contained in the file COPYING at the root of the source code distribution *
+ * tree. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <mchecksum.h> /* Mercury Checksum library */
+#include "H5VLiod_common.h"
+
+/*
+ * Local typedefs
+ */
+/* Structure for a compound member type */
+typedef struct H5VL_iod_cmpd_info_t {
+ size_t offset;
+ hid_t type_id;
+} H5VL_iod_cmpd_info_t;
+
+/* Macros for error handling */
+#define SUCCEED 0
+#define FAIL -1
+#define PRINT_ERROR(MSG) \
+do { \
+ fprintf(stderr, "ERROR at %s:%d in %s()...\n%s\n", __FILE__, __LINE__, __FUNCTION__,MSG); \
+} while(0)
+#define ERROR(MSG) \
+do { \
+ PRINT_ERROR(MSG); \
+ goto error; \
+} while(0)
+
+#define TRUE 1
+#define FALSE 0
+
+/* Macros to encode and decode a uint64_t */
+# define UINT64ENCODE(p, n) \
+ do { \
+ uint64_t _n = (n); \
+ size_t _i; \
+ uint8_t *_p = (uint8_t*)(p); \
+\
+ for (_i = 0; _i < sizeof(uint64_t); _i++, _n >>= 8) \
+ *_p++ = (uint8_t)(_n & 0xff); \
+ for (/*void*/; _i < 8; _i++) \
+ *_p++ = 0; \
+ } while(0)
+
+# define UINT64DECODE(p, n) \
+ do { \
+ /* WE DON'T CHECK FOR OVERFLOW! */ \
+ size_t _i; \
+ uint8_t *_p = (uint8_t*)(p); \
+\
+ n = 0; \
+ (_p) += 8; \
+ for (_i = 0; _i < sizeof(uint64_t); _i++) \
+ n = (n << 8) | *(--_p); \
+ } while(0)
+
+/*
+ * Local functions
+ */
+static int H5VL_iod_cmpd_qsort_cb(const void *_memb1, const void *_memb2);
+static int H5VL_iod_get_type_info_helper(hid_t type_id,
+ H5VL_iod_type_info_t *type_info, size_t offset, size_t *vls_nalloc);
+static int H5VL_iod_cs_send_helper(char *buf, H5VL_iod_type_info_t *type_info,
+ size_t nelem, hg_bulk_segment_t **segments, size_t *num_segments,
+ size_t *segments_nalloc, char **vl_lengths, size_t *vl_lengths_nused,
+ size_t *vl_lengths_nalloc, void ***free_list, size_t *free_list_len,
+ size_t *free_list_nalloc);
+static int H5VL_iod_cs_recv_helper(char *buf, H5VL_iod_type_info_t *type_info,
+ size_t nelem, hg_bulk_segment_t **segments, size_t *num_segments,
+ size_t *segments_nalloc, char *vl_lengths, size_t *vl_lengths_loc,
+ size_t vl_lengths_nused, void ***free_list, size_t *free_list_len,
+ size_t *free_list_nalloc);
+
+
+/*
+ * Local macros
+ */
+#define H5VL_IOD_ARR_ADD(TYPE, ARR, NUSED, NALLOC, DEF_ALLOC) \
+ do { \
+ size_t _tmp_nalloc; \
+ TYPE *_tmp_arr; \
+\
+ assert((NALLOC) >= (NUSED)); \
+\
+ if((NALLOC) == (NUSED)) { \
+ _tmp_nalloc = (NALLOC) ? (NALLOC) * 2 : (DEF_ALLOC); \
+\
+ if(NULL == (_tmp_arr = (TYPE *)realloc(ARR, _tmp_nalloc * sizeof(TYPE)))) \
+ ERROR("failed to reallocate array"); \
+ (ARR) = _tmp_arr; \
+ (NALLOC) = _tmp_nalloc; \
+ } /* end if */ \
+ } while(0)
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VL_iod_cmpd_qsort_cb
+ *
+ * Purpose: qsort callback for sorting compound type members by
+ * offset.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Nov 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5VL_iod_cmpd_qsort_cb(const void *_memb1, const void *_memb2)
+{
+ const H5VL_iod_cmpd_info_t *memb1 = (const H5VL_iod_cmpd_info_t *)_memb1;
+ const H5VL_iod_cmpd_info_t *memb2 = (const H5VL_iod_cmpd_info_t *)_memb2;
+
+ if(memb1->offset < memb2->offset)
+ return -1;
+ else if(memb1->offset > memb2->offset)
+ return 1;
+ else
+ return 0;
+} /* end H5VL_iod_cmpd_qsort_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VL_iod_get_type_info_helper
+ *
+ * Purpose: Recursively searches for variable-length datatypes in the
+ * provided type, filling in the fields in type_info.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Nov 18, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5VL_iod_get_type_info_helper(hid_t type_id, H5VL_iod_type_info_t *type_info,
+ size_t offset, size_t *vls_nalloc)
+{
+ hid_t super_type = -1;
+ hsize_t *dims = NULL;
+ size_t num_cmpd_membs = 0;
+ H5VL_iod_cmpd_info_t *cmpd_membs = NULL;
+ H5T_class_t type_class;
+ int i;
+
+ assert(type_info);
+ assert(vls_nalloc);
+
+ /* Get type class */
+ if(H5T_NO_CLASS == (type_class = H5Tget_class(type_id)))
+ ERROR("failed to get datatype class");
+
+ /* Take different actions depending on class */
+ switch(type_class) {
+ case H5T_COMPOUND:
+ {
+ int nmemb;
+
+ /* Get number of members */
+ if((nmemb = H5Tget_nmembers(type_id)) < 0)
+ ERROR("failed to get number of compound datatype members");
+
+ /* Allocate array of members */
+ if(NULL == (cmpd_membs = (H5VL_iod_cmpd_info_t *)malloc(nmemb * sizeof(H5VL_iod_cmpd_info_t))))
+ ERROR("failed ot allocate array of compound type members");
+
+ /* Get offset and type for all members */
+ for(i = 0; i < nmemb; i++) {
+ cmpd_membs[i].offset = H5Tget_member_offset(type_id, (unsigned)i);
+
+ if((cmpd_membs[i].type_id = H5Tget_member_type(type_id, (unsigned)i)) < 0)
+ ERROR("failed to get compound datatype member type");
+ num_cmpd_membs++;
+ } /* end for */
+
+ /* Sort members by offset */
+ qsort(cmpd_membs, num_cmpd_membs, sizeof(cmpd_membs[0]), H5VL_iod_cmpd_qsort_cb);
+
+ /* Get info for all members */
+ for(i = 0; i < nmemb; i++)
+ if(H5VL_iod_get_type_info_helper(cmpd_membs[i].type_id, type_info, offset + cmpd_membs[i].offset, vls_nalloc) < 0)
+ ERROR("failed to get compound datatype member type info");
+
+ /* Free cmpd_membs. Run in opposite order so if a failure
+ * occurs the error code doesn't try to free types twice */
+ for(i = nmemb - 1; i >= 0; i--) {
+ num_cmpd_membs--;
+ if(H5Tclose(cmpd_membs[i].type_id) < 0)
+ ERROR("failed to close compound member type");
+ } /* end for */
+ free(cmpd_membs);
+ cmpd_membs = NULL;
+
+ break;
+ } /* end block */
+
+ case H5T_ARRAY:
+ {
+ int ndims;
+ size_t array_nelem = 1;
+ size_t orig_num_vls = type_info->num_vls;
+ size_t elem_num_vls;
+ size_t super_type_size;
+ size_t i_size, j_size;
+
+ /* Get array element type */
+ if((super_type = H5Tget_super(type_id)) < 0)
+ ERROR("failed to get array datatype element type");
+
+ /* Get type info for element type (effectively only for the
+ * first element) */
+ if(H5VL_iod_get_type_info_helper(super_type, type_info, offset, vls_nalloc) < 0)
+ ERROR("failed to get array datatype element type info");
+
+ /* If the element type contains any vlens, we must copy the vlen
+ * info for each element in the array */
+ if(type_info->num_vls != orig_num_vls) {
+ assert(type_info->num_vls > orig_num_vls);
+
+ /* Get number of dimensions in array */
+ if((ndims = H5Tget_array_ndims(type_id)) < 0)
+ ERROR("failed to get array datatype number of dimensions");
+
+ /* Allocate array of dimensions */
+ if(NULL == (dims = (hsize_t *)malloc(ndims * sizeof(hsize_t))))
+ ERROR("failed to allocate array of dimensions");
+
+ /* Get array dimensions */
+ if(H5Tget_array_dims2(type_id, dims) < 0)
+ ERROR("failed to get array datatype dimensions");
+
+ /* Calculate total number of elements */
+ for(i = 0; i < ndims; i++)
+ array_nelem *= (size_t)dims[i];
+
+ /* Get size of element type */
+ if(0 == (super_type_size = H5Tget_size(super_type)))
+ ERROR("failed to get array element type size");
+
+ /* Replicate all vls added during recursion into element
+ * type for each element in the array. Increment ref count
+ * on base types instead of copying. */
+ elem_num_vls = type_info->num_vls;
+ for(i_size = 1; i_size < array_nelem; i_size++)
+ for(j_size = orig_num_vls; j_size < elem_num_vls;
+ j_size++) {
+ H5VL_IOD_ARR_ADD(H5VL_iod_vl_info_t, type_info->vls, type_info->num_vls, *vls_nalloc, 8);
+
+ type_info->vls[type_info->num_vls].offset = type_info->vls[j_size].offset + (i_size * super_type_size);
+ type_info->vls[type_info->num_vls].base_type = type_info->vls[j_size].base_type;
+ if(type_info->vls[type_info->num_vls].base_type)
+ type_info->vls[type_info->num_vls].base_type->rc++;
+ type_info->num_vls++;
+ } /* end for */
+
+ free(dims);
+ dims = NULL;
+ } /* end if */
+
+ if(H5Tclose(super_type) < 0)
+ ERROR("failed to close array datatype element type");
+ super_type = -1;
+
+ break;
+ } /* end block */
+
+ case H5T_VLEN:
+ /* Add vlen to vls array */
+ H5VL_IOD_ARR_ADD(H5VL_iod_vl_info_t, type_info->vls, type_info->num_vls, *vls_nalloc, 8);
+
+ /* Get vlen base type */
+ if((super_type = H5Tget_super(type_id)) < 0)
+ ERROR("failed to get vlen datatype base type");
+
+ /* Set vlen offset in type */
+ type_info->vls[type_info->num_vls].offset = offset;
+
+ /* Allocate type info for base type */
+ if(NULL == (type_info->vls[type_info->num_vls].base_type = (H5VL_iod_type_info_t *)malloc(sizeof(H5VL_iod_type_info_t))))
+ ERROR("failed to allocate vlen datatype base type info");
+ type_info->num_vls++;
+
+ /* Get type info for base type */
+ if(H5VL_iod_get_type_info(super_type, type_info->vls[type_info->num_vls - 1].base_type) < 0)
+ ERROR("failed to get vlen datatype base type info");
+
+ if(H5Tclose(super_type) < 0)
+ ERROR("failed to close vlen datatype base type");
+ super_type = -1;
+
+ break;
+
+ case H5T_STRING:
+ {
+ htri_t is_variable_str;
+
+ /* Check if this string is variable length */
+ if((is_variable_str = H5Tis_variable_str(type_id)) < 0)
+ ERROR("failed to determine if type is variable string");
+
+ if(is_variable_str) {
+ /* Add variable-length string to vls array. Set base_type
+ * to NULL. */
+ H5VL_IOD_ARR_ADD(H5VL_iod_vl_info_t, type_info->vls, type_info->num_vls, *vls_nalloc, 8);
+
+ type_info->vls[type_info->num_vls].offset = offset;
+ type_info->vls[type_info->num_vls].base_type = NULL;
+ type_info->num_vls++;
+
+ break;
+ } /* end if */
+
+ /* Fall through if not variable string */
+ } /* end block */
+
+ default:
+ /* Nothing to do currently */
+ break;
+ } /* end switch */
+
+ return(SUCCEED);
+
+error:
+ if(super_type >= 0)
+ if(H5Tclose(super_type) < 0)
+ PRINT_ERROR("failed to close super type");
+ if(dims)
+ free(dims);
+ if(cmpd_membs) {
+ for(i = 0; i < (int)num_cmpd_membs; i++)
+ if(H5Tclose(cmpd_membs[i].type_id) < 0)
+ PRINT_ERROR("failed to close compound member type");
+ free(cmpd_membs);
+ } /* end if */
+
+ return(FAIL);
+} /* end H5VL_iod_get_type_info_helper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VL_iod_get_type_info
+ *
+ * Purpose: Builds the type_info struct given type_id.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Nov 18, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5VL_iod_get_type_info(hid_t type_id, H5VL_iod_type_info_t *type_info)
+{
+ htri_t found_class;
+
+ /* Initialize struct first, so a call to reset() won't cause problems if
+ * something in this function fails */
+ type_info->num_fl_spans = 0;
+ type_info->fl_spans = NULL;
+ type_info->num_vls = 0;
+ type_info->vls = NULL;
+ type_info->rc = 1;
+ if(0 == (type_info->size = H5Tget_size(type_id)))
+ ERROR("H5Tget_size failed");
+
+ /* Check for a vl or string type */
+ if((found_class = H5Tdetect_class(type_id, H5T_VLEN)) < 0)
+ ERROR("failed to search for vlen type class");
+ if(!found_class)
+ if((found_class = H5Tdetect_class(type_id, H5T_STRING)) < 0)
+ ERROR("failed to search for string type class");
+
+ /* Only need to investigate further if the type contains a vlen or string */
+ if(found_class) {
+ size_t vls_nalloc = 0;
+
+ if(H5VL_iod_get_type_info_helper(type_id, type_info, 0, &vls_nalloc) < 0)
+ ERROR("failed to type info");
+ } /* end if */
+
+ /* If any vlens were found, build fixed-length span info */
+ if(type_info->num_vls) {
+ size_t cur_fl_offset = 0;
+ size_t fl_spans_nalloc = 0;
+ size_t i;
+
+ /* Iterate over all vlens */
+ for(i = 0; i < type_info->num_vls; i++) {
+ /* Check if this vlen left a fixed-length gap before it */
+ assert(type_info->vls[i].offset >= cur_fl_offset);
+ if(type_info->vls[i].offset > cur_fl_offset) {
+ /* Create fixed-length span before vl */
+ H5VL_IOD_ARR_ADD(H5VL_iod_fl_span_t, type_info->fl_spans, type_info->num_fl_spans, fl_spans_nalloc, 2);
+
+ type_info->fl_spans[type_info->num_fl_spans].offset = cur_fl_offset;
+ type_info->fl_spans[type_info->num_fl_spans].size = type_info->vls[i].offset - cur_fl_offset;
+ type_info->num_fl_spans++;
+ } /* end if */
+
+ /* Update cur_fl_offset */
+ cur_fl_offset = type_info->vls[i].offset + (type_info->vls[i].base_type ? sizeof(hvl_t) : sizeof(char *));
+ } /* end for */
+
+ /* Add span at end */
+ assert(type_info->size >= cur_fl_offset);
+ if(type_info->size > cur_fl_offset) {
+ H5VL_IOD_ARR_ADD(H5VL_iod_fl_span_t, type_info->fl_spans, type_info->num_fl_spans, fl_spans_nalloc, 2);
+
+ type_info->fl_spans[type_info->num_fl_spans].offset = cur_fl_offset;
+ type_info->fl_spans[type_info->num_fl_spans].size = type_info->size - cur_fl_offset;
+ type_info->num_fl_spans++;
+ } /* end if */
+ } /* end if */
+
+ return(SUCCEED);
+
+error:
+ H5VL_iod_type_info_reset(type_info);
+
+ return(FAIL);
+} /* end H5VL_iod_get_type_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VL_iod_type_info_reset
+ *
+ * Purpose: Frees all fields fields in type_info, and anything
+ * referenced by those fields. Does not free type_info.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Nov 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5VL_iod_type_info_reset(H5VL_iod_type_info_t *type_info)
+{
+ size_t i;
+
+ /* Free fl spans */
+ if(type_info->fl_spans) {
+ free(type_info->fl_spans);
+ type_info->fl_spans = NULL;
+ } /* end if */
+ type_info->num_fl_spans = 0;
+
+ /* Free vls */
+ if(type_info->vls) {
+ /* Recurse into each vl's base type, and free the base type if its rc
+ * reaches 0 */
+ for(i = 0; i < type_info->num_vls; i++)
+ if(type_info->vls[i].base_type
+ && (--type_info->vls[i].base_type->rc == 0)) {
+ H5VL_iod_type_info_reset(type_info->vls[i].base_type);
+ free(type_info->vls[i].base_type);
+ } /* end if */
+
+ free(type_info->vls);
+ type_info->vls = NULL;
+ } /* end if */
+ type_info->num_vls = 0;
+
+ return;
+} /* end H5VL_iod_type_info_reset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VL_iod_cs_send_helper
+ *
+ * Purpose: Recursively builds the segments array and array of
+ * variable-length data lengths given buf, type_info and
+ * nelem.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Nov 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5VL_iod_cs_send_helper(char *buf, H5VL_iod_type_info_t *type_info,
+ size_t nelem, hg_bulk_segment_t **segments, size_t *num_segments,
+ size_t *segments_nalloc, char **vl_lengths, size_t *vl_lengths_nused,
+ size_t *vl_lengths_nalloc, void ***free_list, size_t *free_list_len,
+ size_t *free_list_nalloc)
+{
+ _Bool wrapped = FALSE;
+ _Bool wrappable;
+ size_t span_size;
+ size_t i;
+ size_t j;
+
+ assert(nelem > 0);
+
+ if(type_info->vls) {
+ /* Add segments for fixed-length spans */
+ if(type_info->num_fl_spans > 0) {
+ assert(type_info->fl_spans);
+
+ /* Check if we can combine the last span in each element with the first
+ * span in the next */
+ wrappable = ((type_info->fl_spans[type_info->num_fl_spans - 1].offset
+ + type_info->fl_spans[type_info->num_fl_spans - 1].size)
+ == type_info->size) && (type_info->fl_spans[0].offset == 0);
+
+ assert(!(wrappable && (type_info->num_fl_spans == 1)));
+
+ /* Iterate over spans */
+ for(i = 0; i < nelem; i++)
+ for(j = 0; j < type_info->num_fl_spans; j++)
+ if(wrapped)
+ wrapped = FALSE;
+ else {
+ /* Add fixed-length segment to segments array */
+ H5VL_IOD_ARR_ADD(hg_bulk_segment_t, *segments, *num_segments, *segments_nalloc, 256);
+
+ /* Check if we can wrap this segment */
+ if((j == (type_info->num_fl_spans - 1)) && wrappable
+ && (i != (nelem - 1))) {
+ span_size = type_info->fl_spans[0].size + type_info->fl_spans[j].size;
+ wrapped = TRUE;
+ } /* end if */
+ else
+ span_size = type_info->fl_spans[j].size;
+
+ /* Add segment */
+ (*segments)[*num_segments].address = (hg_ptr_t)(buf + (i * type_info->size) + type_info->fl_spans[j].offset);
+ (*segments)[*num_segments].size = span_size;
+ (*num_segments)++;
+ } /* end else */
+ } /* end if */
+
+ /* Analyze vlens */
+ for(i = 0; i < nelem; i++)
+ for(j = 0; j < type_info->num_vls; j++)
+ if(type_info->vls[j].base_type) {
+ /* Standard vlen */
+ hvl_t vl = *(hvl_t *)(buf + (i * type_info->size) + type_info->vls[j].offset);
+
+ /* Add vl segment length to vl_lengths array */
+ H5VL_IOD_ARR_ADD(char, *vl_lengths, *vl_lengths_nused, *vl_lengths_nalloc, 256);
+ assert(*vl_lengths_nused + 8 <= *vl_lengths_nalloc);
+
+ UINT64ENCODE(&(*vl_lengths)[*vl_lengths_nused], (uint64_t)vl.len);
+ *vl_lengths_nused += 8;
+
+ /* Handle vlen array if present */
+ if(vl.len > 0) {
+ /* Add vlen buffer to free list, if present */
+ if(free_list) {
+ H5VL_IOD_ARR_ADD(void *, *free_list, *free_list_len, *free_list_nalloc, 64);
+
+ (*free_list)[*free_list_len] = vl.p;
+ (*free_list_len)++;
+ } /* end if */
+
+ /* Recurse into vlen data */
+ if(H5VL_iod_cs_send_helper(vl.p, type_info->vls[j].base_type, vl.len, segments, num_segments, segments_nalloc, vl_lengths, vl_lengths_nused, vl_lengths_nalloc, free_list, free_list_len, free_list_nalloc) < 0)
+ ERROR("failed to build segments");
+ } /* end if */
+ } /* end if */
+ else {
+ /* Vlen string */
+ char *vl_s = *(char **)(buf + (i * type_info->size) + type_info->vls[j].offset);
+ uint64_t vl_s_len;
+
+ /* Get size */
+ if(vl_s)
+ vl_s_len = (uint64_t)strlen(vl_s) + 1;
+ else
+ vl_s_len = 0;
+
+ /* Add vl string length to vl_lengths array. Include null
+ * terminator in length to distinguish between NULL pointer
+ * (len = 0) and null string (len = 1) */
+ H5VL_IOD_ARR_ADD(char, *vl_lengths, *vl_lengths_nused, *vl_lengths_nalloc, 256);
+ assert(*vl_lengths_nused + 8 <= *vl_lengths_nalloc);
+
+ UINT64ENCODE(&(*vl_lengths)[*vl_lengths_nused], vl_s_len);
+ *vl_lengths_nused += 8;
+
+ /* Handle the vl string buffer if present */
+ if(vl_s_len > 0) {
+ /* Add vl string buffer to free list, if present */
+ if(free_list) {
+ H5VL_IOD_ARR_ADD(void *, *free_list, *free_list_len, *free_list_nalloc, 64);
+
+ (*free_list)[*free_list_len] = vl_s;
+ (*free_list_len)++;
+ } /* end if */
+
+ /* Add vl string length to segments array, if length is
+ * greater than 1 (including null terminator). Do not
+ * include null terminator in segment length so it is not
+ * transmitted. */
+ if(vl_s_len > 1) {
+ H5VL_IOD_ARR_ADD(hg_bulk_segment_t, *segments, *num_segments, *segments_nalloc, 256);
+
+ (*segments)[*num_segments].address = (hg_ptr_t)vl_s;
+ (*segments)[*num_segments].size = vl_s_len - 1;
+ (*num_segments)++;
+ } /* end if */
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ else {
+ /* No vlens, just add entire buffer to segments array */
+ H5VL_IOD_ARR_ADD(hg_bulk_segment_t, *segments, *num_segments, *segments_nalloc, 256);
+
+ (*segments)[*num_segments].address = (hg_ptr_t)buf;
+ (*segments)[*num_segments].size = nelem * type_info->size;
+ (*num_segments)++;
+ } /* end else */
+
+ return(SUCCEED);
+
+error:
+ return(FAIL);
+} /* end H5VL_iod_cs_send_helper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VL_iod_create_segments_send
+ *
+ * Purpose: Builds the segments array and array of variable-length
+ * data lengths given buf, type_info and nelem.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Nov 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5VL_iod_create_segments_send(char *buf, H5VL_iod_type_info_t *type_info,
+ size_t nelem, hg_bulk_segment_t **segments, size_t *num_segments,
+ char **vl_lengths, size_t *vl_lengths_size, void ***free_list,
+ size_t *free_list_len)
+{
+ size_t segments_nalloc = 0;
+ size_t vl_lengths_nalloc = 0;
+ size_t free_list_nalloc = 0;
+
+ assert(buf);
+ assert(type_info);
+ assert(type_info->vls);
+ assert(nelem > 0);
+ assert(segments);
+ assert(!*segments);
+ assert(num_segments);
+ assert(*num_segments == 0);
+ assert(vl_lengths);
+ assert(!*vl_lengths);
+ assert(vl_lengths_size);
+ assert(*vl_lengths_size == 0);
+ assert(!free_list == !free_list_len);
+ assert(!free_list || !*free_list);
+ assert(!free_list_len || (*free_list_len == 0));
+
+ /* Call the real (recursive) function */
+ if(H5VL_iod_cs_send_helper(buf, type_info, nelem, segments, num_segments, &segments_nalloc, vl_lengths, vl_lengths_size, &vl_lengths_nalloc, free_list, free_list_len, &free_list_nalloc) < 0)
+ ERROR("failed to build segments");
+
+ return(SUCCEED);
+
+error:
+ return(FAIL);
+} /* end H5VL_iod_create_segments_send() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VL_iod_cs_recv_helper
+ *
+ * Purpose: Recursively builds the segments array, allocates buffers
+ * for variable-length data, and writes vlen pointers given
+ * (empty) buf, type_info, nelem, and the vl_lengths array.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Nov 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5VL_iod_cs_recv_helper(char *buf, H5VL_iod_type_info_t *type_info,
+ size_t nelem, hg_bulk_segment_t **segments, size_t *num_segments,
+ size_t *segments_nalloc, char *vl_lengths, size_t *vl_lengths_loc,
+ size_t vl_lengths_size, void ***free_list, size_t *free_list_len,
+ size_t *free_list_nalloc)
+{
+ _Bool wrapped = FALSE;
+ _Bool wrappable;
+ size_t span_size;
+ size_t i;
+ size_t j;
+
+ assert(nelem > 0);
+
+ if(type_info->vls) {
+ /* Add segments for fixed-length spans */
+ if(type_info->num_fl_spans > 0) {
+ assert(type_info->fl_spans);
+
+ /* Check if we can combine the last span in each element with the first
+ * span in the next */
+ wrappable = ((type_info->fl_spans[type_info->num_fl_spans - 1].offset
+ + type_info->fl_spans[type_info->num_fl_spans - 1].size)
+ == type_info->size) && (type_info->fl_spans[0].offset == 0);
+
+ assert(!(wrappable && (type_info->num_fl_spans == 1)));
+
+ /* Iterate over spans */
+ for(i = 0; i < nelem; i++)
+ for(j = 0; j < type_info->num_fl_spans; j++)
+ if(wrapped)
+ wrapped = FALSE;
+ else {
+ /* Add fixed-length segment to segments array */
+ H5VL_IOD_ARR_ADD(hg_bulk_segment_t, *segments, *num_segments, *segments_nalloc, 256);
+
+ /* Check if we can wrap this segment */
+ if((j == (type_info->num_fl_spans - 1)) && wrappable
+ && (i != (nelem - 1))) {
+ span_size = type_info->fl_spans[0].size + type_info->fl_spans[j].size;
+ wrapped = TRUE;
+ } /* end if */
+ else
+ span_size = type_info->fl_spans[j].size;
+
+ /* Add segment */
+ (*segments)[*num_segments].address = (hg_ptr_t)(buf + (i * type_info->size) + type_info->fl_spans[j].offset);
+ (*segments)[*num_segments].size = span_size;
+ (*num_segments)++;
+ } /* end else */
+ } /* end if */
+
+ /* Analyze vlens */
+ for(i = 0; i < nelem; i++)
+ for(j = 0; j < type_info->num_vls; j++)
+ if(type_info->vls[j].base_type) {
+ /* Standard vlen */
+ hvl_t *vl = (hvl_t *)(buf + (i * type_info->size) + type_info->vls[j].offset);
+ uint64_t vl_length;
+
+ /* Retrieve vl segment length from vl_lengths array */
+ if(*vl_lengths_loc + 8 > vl_lengths_size)
+ ERROR("vl_lengths array is too short");
+ UINT64DECODE(&vl_lengths[*vl_lengths_loc], vl_length);
+ *vl_lengths_loc += 8;
+ vl->len = (size_t)vl_length;
+
+ if(vl_length == 0)
+ vl->p = NULL;
+ else {
+ /* Allocate buffer for vlen data */
+ if(NULL == (vl->p = malloc(vl_length * type_info->vls[j].base_type->size)))
+ ERROR("failed to allocate vlen buffer");
+
+ /* Add malloc'ed buffer to free list, if present */
+ if(free_list) {
+ H5VL_IOD_ARR_ADD(void *, *free_list, *free_list_len, *free_list_nalloc, 64);
+
+ (*free_list)[*free_list_len] = vl->p;
+ (*free_list_len)++;
+ } /* end if */
+
+ /* Recurse into vlen data */
+ if(H5VL_iod_cs_recv_helper(vl->p, type_info->vls[j].base_type, (size_t)vl_length, segments, num_segments, segments_nalloc, vl_lengths, vl_lengths_loc, vl_lengths_size, free_list, free_list_len, free_list_nalloc) < 0)
+ ERROR("failed to build segments");
+ } /* end if */
+ } /* end if */
+ else {
+ /* Vlen string */
+ char **vl_s = (char **)(buf + (i * type_info->size) + type_info->vls[j].offset);
+ uint64_t vl_s_len;
+
+ /* Retrieve vl string length from vl_lengths array */
+ if(*vl_lengths_loc + 8 > vl_lengths_size)
+ ERROR("vl_lengths array is too short");
+ UINT64DECODE(&vl_lengths[*vl_lengths_loc], vl_s_len);
+ *vl_lengths_loc += 8;
+
+ if(vl_s_len == 0)
+ *vl_s = NULL;
+ else {
+ /* Allocate buffer for vlen string data */
+ if(NULL == (*vl_s = malloc((size_t)vl_s_len)))
+ ERROR("failed to allocate vlen string buffer");
+
+ /* Add malloc'ed buffer to free list, if present */
+ if(free_list) {
+ H5VL_IOD_ARR_ADD(void *, *free_list, *free_list_len, *free_list_nalloc, 64);
+
+ (*free_list)[*free_list_len] = *vl_s;
+ (*free_list_len)++;
+ } /* end if */
+
+ /* Add vl string to segments array, if length is greater
+ * than 1 (including null terminator) */
+ if(vl_s_len > 1) {
+ H5VL_IOD_ARR_ADD(hg_bulk_segment_t, *segments, *num_segments, *segments_nalloc, 256);
+
+ (*segments)[*num_segments].address = (hg_ptr_t)*vl_s;
+ (*segments)[*num_segments].size = (size_t)vl_s_len - 1;
+ (*num_segments)++;
+ } /* end if */
+
+ /* Add null terminator */
+ (*vl_s)[vl_s_len - 1] = '\0';
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ else {
+ /* No vlens, just add entire buffer to segments array */
+ H5VL_IOD_ARR_ADD(hg_bulk_segment_t, *segments, *num_segments, *segments_nalloc, 256);
+
+ (*segments)[*num_segments].address = (hg_ptr_t)buf;
+ (*segments)[*num_segments].size = nelem * type_info->size;
+ (*num_segments)++;
+ } /* end else */
+
+ return(SUCCEED);
+
+error:
+ return(FAIL);
+} /* end H5VL_iod_cs_recv_helper() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VL_iod_create_segments_recv
+ *
+ * Purpose: Builds the segments array, allocates buffers for
+ * variable-length data, and writes vlen pointers given
+ * (empty) buf, type_info, nelem, and the vl_lengths array.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ *
+ * Programmer: Neil Fortner
+ * Nov 19, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5VL_iod_create_segments_recv(char *buf, H5VL_iod_type_info_t *type_info,
+ size_t nelem, hg_bulk_segment_t **segments, size_t *num_segments,
+ char *vl_lengths, size_t vl_lengths_size, void ***free_list,
+ size_t *free_list_len)
+{
+ size_t segments_nalloc = 0;
+ size_t vl_lengths_loc = 0;
+ size_t free_list_nalloc = 0;
+
+ assert(buf);
+ assert(type_info);
+ assert(type_info->vls);
+ assert(nelem > 0);
+ assert(segments);
+ assert(!*segments);
+ assert(num_segments);
+ assert(*num_segments == 0);
+ assert(vl_lengths);
+ assert(vl_lengths_size > 0);
+ assert(!free_list == !free_list_len);
+ assert(!free_list || !*free_list);
+ assert(!free_list_len || (*free_list_len == 0));
+
+ /* Call the real (recursive) function */
+ if(H5VL_iod_cs_recv_helper(buf, type_info, nelem, segments, num_segments, &segments_nalloc, vl_lengths, &vl_lengths_loc, vl_lengths_size, free_list, free_list_len, &free_list_nalloc) < 0)
+ ERROR("failed to build segments");
+
+ return(SUCCEED);
+
+error:
+ return(FAIL);
+} /* end H5VL_iod_create_segments_recv() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5VL_iod_free_list_free
+ *
+ * Purpose: Frees all pointers on the provided free list and then
+ * frees the free list itself
+ *
+ * Return: void
+ *
+ * Programmer: Neil Fortner
+ * Dec 5, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+void
+H5VL_iod_free_list_free(void **free_list, size_t free_list_len)
+{
+ size_t i;
+
+ for(i = 0; i < free_list_len; i++)
+ free(free_list[i]);
+ free(free_list);
+} /* end H5VL_iod_free_list_free() */
+
+uint64_t
+H5_checksum_crc64(const void *buf, size_t buf_size)
+{
+ const char *hash_method = "crc64";
+ size_t hash_size;
+ uint64_t hash;
+ mchecksum_object_t checksum;
+
+ /* Initialize checksum */
+ mchecksum_init(hash_method, &checksum);
+
+ /* Update checksum */
+ mchecksum_update(checksum, buf, buf_size);
+
+ /* Get size of checksum */
+ hash_size = mchecksum_get_size(checksum);
+
+ assert(hash_size == sizeof(uint64_t));
+
+ /* get checksum value */
+ mchecksum_get(checksum, &hash, hash_size, 1);
+
+ /* Destroy checksum */
+ mchecksum_destroy(checksum);
+
+ return hash;
+}
+
+uint64_t
+H5_checksum_crc64_segments(hg_bulk_segment_t *segments, size_t count)
+{
+ const char *hash_method = "crc64";
+ size_t hash_size;
+ uint64_t hash;
+ size_t i;
+ mchecksum_object_t checksum;
+
+ /* Initialize checksum */
+ mchecksum_init(hash_method, &checksum);
+
+ /* Update checksum */
+ for (i = 0; i < count; i++) {
+ mchecksum_update(checksum, segments[i].address, segments[i].size);
+ }
+
+ /* Get size of checksum */
+ hash_size = mchecksum_get_size(checksum);
+
+ assert(hash_size == sizeof(uint64_t));
+
+ /* get checksum value */
+ mchecksum_get(checksum, &hash, hash_size, 1);
+
+ /* Destroy checksum */
+ mchecksum_destroy(checksum);
+
+ return hash;
+}
+
+uint64_t
+H5_checksum_crc64_fragments(void **buf, size_t *buf_size, size_t count)
+{
+ const char *hash_method = "crc64";
+ size_t hash_size;
+ uint64_t hash;
+ size_t i;
+ mchecksum_object_t checksum;
+
+ /* Initialize checksum */
+ mchecksum_init(hash_method, &checksum);
+
+ /* Update checksum */
+ for (i = 0; i < count; i++) {
+ mchecksum_update(checksum, buf[i], buf_size[i]);
+ }
+
+ /* Get size of checksum */
+ hash_size = mchecksum_get_size(checksum);
+
+ assert(hash_size == sizeof(uint64_t));
+
+ /* get checksum value */
+ mchecksum_get(checksum, &hash, hash_size, 1);
+
+ /* Destroy checksum */
+ mchecksum_destroy(checksum);
+
+ return hash;
+}