Coverage Report

Created: 2025-11-03 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Dscatgath.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/****************/
14
/* Module Setup */
15
/****************/
16
17
#include "H5Dmodule.h" /* This source code file is part of the H5D module */
18
19
/***********/
20
/* Headers */
21
/***********/
22
#include "H5private.h"   /* Generic Functions     */
23
#include "H5CXprivate.h" /* API Contexts                         */
24
#include "H5Dpkg.h"      /* Dataset functions     */
25
#include "H5Eprivate.h"  /* Error handling        */
26
#include "H5FLprivate.h" /* Free Lists                           */
27
#include "H5MMprivate.h" /* Memory management     */
28
29
/****************/
30
/* Local Macros */
31
/****************/
32
33
/* Macro to determine if we're using H5D__compound_opt_read() */
34
#define H5D__SCATGATH_USE_CMPD_OPT_READ(DSET_INFO, IN_PLACE_TCONV)                                           \
35
0
    ((DSET_INFO)->type_info.cmpd_subset && H5T_SUBSET_FALSE != (DSET_INFO)->type_info.cmpd_subset->subset && \
36
0
     !(IN_PLACE_TCONV))
37
38
/* Macro to determine if we're using H5D__compound_opt_write() */
39
#define H5D__SCATGATH_USE_CMPD_OPT_WRITE(DSET_INFO, IN_PLACE_TCONV)                                          \
40
0
    ((DSET_INFO)->type_info.cmpd_subset && H5T_SUBSET_DST == (DSET_INFO)->type_info.cmpd_subset->subset &&   \
41
0
     (DSET_INFO)->type_info.dst_type_size == (DSET_INFO)->type_info.cmpd_subset->copy_size &&                \
42
0
     !(IN_PLACE_TCONV))
43
44
/******************/
45
/* Local Typedefs */
46
/******************/
47
48
/********************/
49
/* Local Prototypes */
50
/********************/
51
static herr_t H5D__scatter_file(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info,
52
                                H5S_sel_iter_t *file_iter, size_t nelmts, const void *buf);
53
static size_t H5D__gather_file(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info,
54
                               H5S_sel_iter_t *file_iter, size_t nelmts, void *buf);
55
static herr_t H5D__compound_opt_read(size_t nelmts, H5S_sel_iter_t *iter, const H5D_type_info_t *type_info,
56
                                     uint8_t *tconv_buf, void *user_buf /*out*/);
57
static herr_t H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info, void *tconv_buf);
58
59
/*********************/
60
/* Package Variables */
61
/*********************/
62
63
/*******************/
64
/* Local Variables */
65
/*******************/
66
67
/* Declare extern free list to manage the H5S_sel_iter_t struct */
68
H5FL_EXTERN(H5S_sel_iter_t);
69
70
/* Declare extern free list to manage sequences of size_t */
71
H5FL_SEQ_EXTERN(size_t);
72
73
/* Declare extern free list to manage sequences of hsize_t */
74
H5FL_SEQ_EXTERN(hsize_t);
75
76
/*-------------------------------------------------------------------------
77
 * Function:  H5D__scatter_file
78
 *
79
 * Purpose: Scatters dataset elements from the type conversion buffer BUF
80
 *    to the file F where the data points are arranged according to
81
 *    the file dataspace FILE_SPACE and stored according to
82
 *    LAYOUT and EFL. Each element is ELMT_SIZE bytes.
83
 *    The caller is requesting that NELMTS elements are copied.
84
 *
85
 * Return:  Non-negative on success/Negative on failure
86
 *
87
 *-------------------------------------------------------------------------
88
 */
89
static herr_t
90
H5D__scatter_file(const H5D_io_info_t *_io_info, const H5D_dset_io_info_t *_dset_info, H5S_sel_iter_t *iter,
91
                  size_t nelmts, const void *_buf)
92
0
{
93
0
    H5D_io_info_t      tmp_io_info;           /* Temporary I/O info object */
94
0
    H5D_dset_io_info_t tmp_dset_info;         /* Temporary I/O info object */
95
0
    hsize_t           *off = NULL;            /* Pointer to sequence offsets */
96
0
    hsize_t            mem_off;               /* Offset in memory */
97
0
    size_t             mem_curr_seq;          /* "Current sequence" in memory */
98
0
    size_t             dset_curr_seq;         /* "Current sequence" in dataset */
99
0
    size_t            *len = NULL;            /* Array to store sequence lengths */
100
0
    size_t             orig_mem_len, mem_len; /* Length of sequence in memory */
101
0
    size_t             nseq;                  /* Number of sequences generated */
102
0
    size_t             nelem;                 /* Number of elements used in sequences */
103
0
    size_t             dxpl_vec_size;         /* Vector length from API context's DXPL */
104
0
    size_t             vec_size;              /* Vector length */
105
0
    herr_t             ret_value = SUCCEED;   /* Return value */
106
107
0
    FUNC_ENTER_PACKAGE
108
109
    /* Check args */
110
0
    assert(_io_info);
111
0
    assert(_dset_info);
112
0
    assert(_dset_info->dset);
113
0
    assert(_dset_info->store);
114
0
    assert(iter);
115
0
    assert(nelmts > 0);
116
0
    assert(_buf);
117
118
    /* Set up temporary I/O info object */
119
0
    H5MM_memcpy(&tmp_io_info, _io_info, sizeof(*_io_info));
120
0
    H5MM_memcpy(&tmp_dset_info, _dset_info, sizeof(*_dset_info));
121
0
    tmp_io_info.op_type    = H5D_IO_OP_WRITE;
122
0
    tmp_dset_info.buf.cvp  = _buf;
123
0
    tmp_io_info.dsets_info = &tmp_dset_info;
124
125
    /* Get info from API context */
126
0
    if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
127
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve I/O vector size");
128
129
    /* Allocate the vector I/O arrays */
130
0
    if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
131
0
        vec_size = dxpl_vec_size;
132
0
    else
133
0
        vec_size = H5D_IO_VECTOR_SIZE;
134
0
    if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
135
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array");
136
0
    if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
137
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array");
138
139
    /* Loop until all elements are written */
140
0
    while (nelmts > 0) {
141
        /* Get list of sequences for selection to write */
142
0
        if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
143
0
            HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed");
144
145
        /* Reset the current sequence information */
146
0
        mem_curr_seq = dset_curr_seq = 0;
147
0
        orig_mem_len = mem_len = nelem * iter->elmt_size;
148
0
        mem_off                = 0;
149
150
        /* Write sequence list out */
151
0
        if ((*tmp_dset_info.layout_ops.writevv)(&tmp_io_info, &tmp_dset_info, nseq, &dset_curr_seq, len, off,
152
0
                                                (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0)
153
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error");
154
155
        /* Update buffer */
156
0
        tmp_dset_info.buf.cvp = (const uint8_t *)tmp_dset_info.buf.cvp + orig_mem_len;
157
158
        /* Decrement number of elements left to process */
159
0
        nelmts -= nelem;
160
0
    } /* end while */
161
162
0
done:
163
    /* Release resources, if allocated */
164
0
    if (len)
165
0
        len = H5FL_SEQ_FREE(size_t, len);
166
0
    if (off)
167
0
        off = H5FL_SEQ_FREE(hsize_t, off);
168
169
0
    FUNC_LEAVE_NOAPI(ret_value)
170
0
} /* H5D__scatter_file() */
171
172
/*-------------------------------------------------------------------------
173
 * Function:  H5D__gather_file
174
 *
175
 * Purpose: Gathers data points from file F and accumulates them in the
176
 *    type conversion buffer BUF.  The LAYOUT argument describes
177
 *    how the data is stored on disk and EFL describes how the data
178
 *    is organized in external files.  ELMT_SIZE is the size in
179
 *    bytes of a datum which this function treats as opaque.
180
 *    FILE_SPACE describes the dataspace of the dataset on disk
181
 *    and the elements that have been selected for reading (via
182
 *    hyperslab, etc).  This function will copy at most NELMTS
183
 *    elements.
184
 *
185
 * Return:  Success:  Number of elements copied.
186
 *    Failure:  0
187
 *
188
 *-------------------------------------------------------------------------
189
 */
190
static size_t
191
H5D__gather_file(const H5D_io_info_t *_io_info, const H5D_dset_io_info_t *_dset_info, H5S_sel_iter_t *iter,
192
                 size_t nelmts, void *_buf /*out*/)
193
0
{
194
0
    H5D_io_info_t      tmp_io_info;           /* Temporary I/O info object */
195
0
    H5D_dset_io_info_t tmp_dset_info;         /* Temporary I/O info object */
196
0
    hsize_t           *off = NULL;            /* Pointer to sequence offsets */
197
0
    hsize_t            mem_off;               /* Offset in memory */
198
0
    size_t             mem_curr_seq;          /* "Current sequence" in memory */
199
0
    size_t             dset_curr_seq;         /* "Current sequence" in dataset */
200
0
    size_t            *len = NULL;            /* Pointer to sequence lengths */
201
0
    size_t             orig_mem_len, mem_len; /* Length of sequence in memory */
202
0
    size_t             nseq;                  /* Number of sequences generated */
203
0
    size_t             nelem;                 /* Number of elements used in sequences */
204
0
    size_t             dxpl_vec_size;         /* Vector length from API context's DXPL */
205
0
    size_t             vec_size;              /* Vector length */
206
0
    size_t             ret_value = nelmts;    /* Return value */
207
208
0
    FUNC_ENTER_PACKAGE
209
210
    /* Check args */
211
0
    assert(_io_info);
212
0
    assert(_dset_info);
213
0
    assert(_dset_info->dset);
214
0
    assert(_dset_info->store);
215
0
    assert(iter);
216
0
    assert(nelmts > 0);
217
0
    assert(_buf);
218
219
    /* Set up temporary I/O info object */
220
0
    H5MM_memcpy(&tmp_io_info, _io_info, sizeof(*_io_info));
221
0
    H5MM_memcpy(&tmp_dset_info, _dset_info, sizeof(*_dset_info));
222
0
    tmp_io_info.op_type    = H5D_IO_OP_READ;
223
0
    tmp_dset_info.buf.vp   = _buf;
224
0
    tmp_io_info.dsets_info = &tmp_dset_info;
225
226
    /* Get info from API context */
227
0
    if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
228
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, 0, "can't retrieve I/O vector size");
229
230
    /* Allocate the vector I/O arrays */
231
0
    if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
232
0
        vec_size = dxpl_vec_size;
233
0
    else
234
0
        vec_size = H5D_IO_VECTOR_SIZE;
235
0
    if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
236
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O length vector array");
237
0
    if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
238
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O offset vector array");
239
240
    /* Loop until all elements are read */
241
0
    while (nelmts > 0) {
242
        /* Get list of sequences for selection to read */
243
0
        if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
244
0
            HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed");
245
246
        /* Reset the current sequence information */
247
0
        mem_curr_seq = dset_curr_seq = 0;
248
0
        orig_mem_len = mem_len = nelem * iter->elmt_size;
249
0
        mem_off                = 0;
250
251
        /* Read sequence list in */
252
0
        if ((*tmp_dset_info.layout_ops.readvv)(&tmp_io_info, &tmp_dset_info, nseq, &dset_curr_seq, len, off,
253
0
                                               (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0)
254
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error");
255
256
        /* Update buffer */
257
0
        tmp_dset_info.buf.vp = (uint8_t *)tmp_dset_info.buf.vp + orig_mem_len;
258
259
        /* Decrement number of elements left to process */
260
0
        nelmts -= nelem;
261
0
    } /* end while */
262
263
0
done:
264
    /* Release resources, if allocated */
265
0
    if (len)
266
0
        len = H5FL_SEQ_FREE(size_t, len);
267
0
    if (off)
268
0
        off = H5FL_SEQ_FREE(hsize_t, off);
269
270
0
    FUNC_LEAVE_NOAPI(ret_value)
271
0
} /* H5D__gather_file() */
272
273
/*-------------------------------------------------------------------------
274
 * Function:  H5D__scatter_mem
275
 *
276
 * Purpose: Scatters NELMTS data points from the scatter buffer
277
 *    TSCAT_BUF to the application buffer BUF.  Each element is
278
 *    ELMT_SIZE bytes and they are organized in application memory
279
 *    according to SPACE.
280
 *
281
 * Return:  Non-negative on success/Negative on failure
282
 *
283
 *-------------------------------------------------------------------------
284
 */
285
herr_t
286
H5D__scatter_mem(const void *_tscat_buf, H5S_sel_iter_t *iter, size_t nelmts, void *_buf /*out*/)
287
0
{
288
0
    uint8_t       *buf       = (uint8_t *)_buf; /* Get local copies for address arithmetic */
289
0
    const uint8_t *tscat_buf = (const uint8_t *)_tscat_buf;
290
0
    hsize_t       *off       = NULL;    /* Pointer to sequence offsets */
291
0
    size_t        *len       = NULL;    /* Pointer to sequence lengths */
292
0
    size_t         curr_len;            /* Length of bytes left to process in sequence */
293
0
    size_t         nseq;                /* Number of sequences generated */
294
0
    size_t         curr_seq;            /* Current sequence being processed */
295
0
    size_t         nelem;               /* Number of elements used in sequences */
296
0
    size_t         dxpl_vec_size;       /* Vector length from API context's DXPL */
297
0
    size_t         vec_size;            /* Vector length */
298
0
    herr_t         ret_value = SUCCEED; /* Number of elements scattered */
299
300
0
    FUNC_ENTER_PACKAGE
301
302
    /* Check args */
303
0
    assert(tscat_buf);
304
0
    assert(iter);
305
0
    assert(nelmts > 0);
306
0
    assert(buf);
307
308
    /* Get info from API context */
309
0
    if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
310
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve I/O vector size");
311
312
    /* Allocate the vector I/O arrays */
313
0
    if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
314
0
        vec_size = dxpl_vec_size;
315
0
    else
316
0
        vec_size = H5D_IO_VECTOR_SIZE;
317
0
    if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
318
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array");
319
0
    if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
320
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array");
321
322
    /* Loop until all elements are written */
323
0
    while (nelmts > 0) {
324
        /* Get list of sequences for selection to write */
325
0
        if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
326
0
            HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed");
327
328
        /* Loop, while sequences left to process */
329
0
        for (curr_seq = 0; curr_seq < nseq; curr_seq++) {
330
            /* Get the number of bytes in sequence */
331
0
            curr_len = len[curr_seq];
332
333
0
            H5MM_memcpy(buf + off[curr_seq], tscat_buf, curr_len);
334
335
            /* Advance offset in destination buffer */
336
0
            tscat_buf += curr_len;
337
0
        } /* end for */
338
339
        /* Decrement number of elements left to process */
340
0
        nelmts -= nelem;
341
0
    } /* end while */
342
343
0
done:
344
    /* Release resources, if allocated */
345
0
    if (len)
346
0
        len = H5FL_SEQ_FREE(size_t, len);
347
0
    if (off)
348
0
        off = H5FL_SEQ_FREE(hsize_t, off);
349
350
0
    FUNC_LEAVE_NOAPI(ret_value)
351
0
} /* H5D__scatter_mem() */
352
353
/*-------------------------------------------------------------------------
354
 * Function:  H5D__gather_mem
355
 *
356
 * Purpose: Gathers dataset elements from application memory BUF and
357
 *    copies them into the gather buffer TGATH_BUF.
358
 *    Each element is ELMT_SIZE bytes and arranged in application
359
 *    memory according to SPACE.
360
 *    The caller is requesting that exactly NELMTS be gathered.
361
 *
362
 * Return:  Success:  Number of elements copied.
363
 *    Failure:  0
364
 *
365
 *-------------------------------------------------------------------------
366
 */
367
size_t
368
H5D__gather_mem(const void *_buf, H5S_sel_iter_t *iter, size_t nelmts, void *_tgath_buf /*out*/)
369
0
{
370
0
    const uint8_t *buf       = (const uint8_t *)_buf; /* Get local copies for address arithmetic */
371
0
    uint8_t       *tgath_buf = (uint8_t *)_tgath_buf;
372
0
    hsize_t       *off       = NULL;   /* Pointer to sequence offsets */
373
0
    size_t        *len       = NULL;   /* Pointer to sequence lengths */
374
0
    size_t         curr_len;           /* Length of bytes left to process in sequence */
375
0
    size_t         nseq;               /* Number of sequences generated */
376
0
    size_t         curr_seq;           /* Current sequence being processed */
377
0
    size_t         nelem;              /* Number of elements used in sequences */
378
0
    size_t         dxpl_vec_size;      /* Vector length from API context's DXPL */
379
0
    size_t         vec_size;           /* Vector length */
380
0
    size_t         ret_value = nelmts; /* Number of elements gathered */
381
382
0
    FUNC_ENTER_PACKAGE
383
384
    /* Check args */
385
0
    assert(buf);
386
0
    assert(iter);
387
0
    assert(nelmts > 0);
388
0
    assert(tgath_buf);
389
390
    /* Get info from API context */
391
0
    if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
392
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, 0, "can't retrieve I/O vector size");
393
394
    /* Allocate the vector I/O arrays */
395
0
    if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
396
0
        vec_size = dxpl_vec_size;
397
0
    else
398
0
        vec_size = H5D_IO_VECTOR_SIZE;
399
0
    if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
400
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O length vector array");
401
0
    if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
402
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O offset vector array");
403
404
    /* Loop until all elements are written */
405
0
    while (nelmts > 0) {
406
        /* Get list of sequences for selection to write */
407
0
        if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
408
0
            HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed");
409
410
        /* Loop, while sequences left to process */
411
0
        for (curr_seq = 0; curr_seq < nseq; curr_seq++) {
412
            /* Get the number of bytes in sequence */
413
0
            curr_len = len[curr_seq];
414
415
0
            H5MM_memcpy(tgath_buf, buf + off[curr_seq], curr_len);
416
417
            /* Advance offset in gather buffer */
418
0
            tgath_buf += curr_len;
419
0
        } /* end for */
420
421
        /* Decrement number of elements left to process */
422
0
        nelmts -= nelem;
423
0
    } /* end while */
424
425
0
done:
426
    /* Release resources, if allocated */
427
0
    if (len)
428
0
        len = H5FL_SEQ_FREE(size_t, len);
429
0
    if (off)
430
0
        off = H5FL_SEQ_FREE(hsize_t, off);
431
432
0
    FUNC_LEAVE_NOAPI(ret_value)
433
0
} /* H5D__gather_mem() */
434
435
/*-------------------------------------------------------------------------
436
 * Function:  H5D__scatgath_read
437
 *
438
 * Purpose: Perform scatter/gather ead from a contiguous [piece of a] dataset.
439
 *
440
 * Return:  Non-negative on success/Negative on failure
441
 *
442
 *-------------------------------------------------------------------------
443
 */
444
herr_t
445
H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info)
446
0
{
447
0
    void           *buf;                    /* Local pointer to application buffer */
448
0
    void           *tmp_buf;                /* Buffer to use for type conversion */
449
0
    H5S_sel_iter_t *mem_iter       = NULL;  /* Memory selection iteration info*/
450
0
    bool            mem_iter_init  = false; /* Memory selection iteration info has been initialized */
451
0
    H5S_sel_iter_t *bkg_iter       = NULL;  /* Background iteration info*/
452
0
    bool            bkg_iter_init  = false; /* Background iteration info has been initialized */
453
0
    H5S_sel_iter_t *file_iter      = NULL;  /* File selection iteration info*/
454
0
    bool            file_iter_init = false; /* File selection iteration info has been initialized */
455
0
    hsize_t         smine_start;            /* Strip mine start loc */
456
0
    size_t          smine_nelmts;           /* Elements per strip */
457
0
    bool            in_place_tconv;         /* Whether to perform in-place type_conversion */
458
0
    herr_t          ret_value = SUCCEED;    /* Return value    */
459
460
0
    FUNC_ENTER_PACKAGE
461
462
    /* Sanity check */
463
0
    assert(io_info);
464
0
    assert(dset_info);
465
0
    assert(dset_info->mem_space);
466
0
    assert(dset_info->file_space);
467
0
    assert(dset_info->buf.vp);
468
469
    /* Set buf pointer */
470
0
    buf = dset_info->buf.vp;
471
472
    /* Check for NOOP read */
473
0
    if (dset_info->nelmts == 0)
474
0
        HGOTO_DONE(SUCCEED);
475
476
    /* Check for in-place type conversion */
477
0
    in_place_tconv = dset_info->layout_io_info.contig_piece_info &&
478
0
                     dset_info->layout_io_info.contig_piece_info->in_place_tconv;
479
480
    /* Check if we should disable in-place type conversion for performance.  Do so if we can use the optimized
481
     * compound read function, if this is not a selection I/O operation (so we have normal size conversion
482
     * buffers), and the either entire I/O operation can fit in the type conversion buffer or we need to use a
483
     * background buffer (and therefore could not do the I/O in one operation with in-place conversion
484
     * anyways). */
485
0
    if (in_place_tconv && H5D__SCATGATH_USE_CMPD_OPT_READ(dset_info, false) &&
486
0
        (io_info->use_select_io != H5D_SELECTION_IO_MODE_ON) &&
487
0
        (dset_info->type_info.need_bkg || (dset_info->nelmts <= dset_info->type_info.request_nelmts)))
488
0
        in_place_tconv = false;
489
490
    /* Allocate the iterators */
491
0
    if (NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
492
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator");
493
0
    if (NULL == (bkg_iter = H5FL_MALLOC(H5S_sel_iter_t)))
494
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate background iterator");
495
0
    if (NULL == (file_iter = H5FL_MALLOC(H5S_sel_iter_t)))
496
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator");
497
498
    /* Figure out the strip mine size. */
499
0
    if (H5S_select_iter_init(file_iter, dset_info->file_space, dset_info->type_info.src_type_size,
500
0
                             H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0)
501
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information");
502
0
    file_iter_init = true; /*file selection iteration info has been initialized */
503
0
    if (H5S_select_iter_init(mem_iter, dset_info->mem_space, dset_info->type_info.dst_type_size, 0) < 0)
504
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information");
505
0
    mem_iter_init = true; /*file selection iteration info has been initialized */
506
0
    if (H5S_select_iter_init(bkg_iter, dset_info->mem_space, dset_info->type_info.dst_type_size, 0) < 0)
507
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information");
508
0
    bkg_iter_init = true; /*file selection iteration info has been initialized */
509
510
    /* Start strip mining... */
511
0
    for (smine_start = 0; smine_start < dset_info->nelmts; smine_start += smine_nelmts) {
512
0
        size_t n; /* Elements operated on */
513
514
0
        assert(H5S_SELECT_ITER_NELMTS(file_iter) == (dset_info->nelmts - smine_start));
515
516
        /* Determine strip mine size. First check if we're doing in-place type conversion */
517
0
        if (in_place_tconv) {
518
            /* If this is not a selection I/O operation and there is a background buffer, we cannot exceed
519
             * request_nelmts.  It could be part of a selection I/O operation if this read is used to fill in
520
             * a nonexistent chunk */
521
0
            assert(!H5D__SCATGATH_USE_CMPD_OPT_READ(dset_info, in_place_tconv));
522
0
            if (dset_info->type_info.need_bkg && (io_info->use_select_io != H5D_SELECTION_IO_MODE_ON))
523
0
                smine_nelmts =
524
0
                    (size_t)MIN(dset_info->type_info.request_nelmts, (dset_info->nelmts - smine_start));
525
0
            else {
526
0
                assert(smine_start == 0);
527
0
                smine_nelmts = dset_info->nelmts;
528
0
            }
529
530
            /* Calculate buffer position in user buffer */
531
0
            tmp_buf = (uint8_t *)buf + dset_info->layout_io_info.contig_piece_info->buf_off +
532
0
                      (smine_start * dset_info->type_info.dst_type_size);
533
0
        }
534
0
        else {
535
            /* Do type conversion using intermediate buffer */
536
0
            tmp_buf = io_info->tconv_buf;
537
538
            /* Go figure out how many elements to read from the file */
539
0
            smine_nelmts =
540
0
                (size_t)MIN(dset_info->type_info.request_nelmts, (dset_info->nelmts - smine_start));
541
0
        }
542
543
        /*
544
         * Gather the data from disk into the datatype conversion
545
         * buffer. Also gather data from application to background buffer
546
         * if necessary.
547
         */
548
549
        /* Fill background buffer here unless we will use H5D__compound_opt_read().  Must do this before
550
         * the read so the read buffer doesn't get wiped out if we're using in-place type conversion */
551
0
        if ((H5T_BKG_YES == dset_info->type_info.need_bkg) &&
552
0
            !H5D__SCATGATH_USE_CMPD_OPT_READ(dset_info, in_place_tconv)) {
553
0
            n = H5D__gather_mem(buf, bkg_iter, smine_nelmts, io_info->bkg_buf /*out*/);
554
0
            if (n != smine_nelmts)
555
0
                HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed");
556
0
        }
557
558
        /*
559
         * Gather data
560
         */
561
0
        n = H5D__gather_file(io_info, dset_info, file_iter, smine_nelmts, tmp_buf /*out*/);
562
0
        if (n != smine_nelmts)
563
0
            HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed");
564
565
        /* If the source and destination are compound types and subset of each other
566
         * and no conversion is needed, copy the data directly into user's buffer and
567
         * bypass the rest of steps.
568
         */
569
0
        if (H5D__SCATGATH_USE_CMPD_OPT_READ(dset_info, in_place_tconv)) {
570
0
            if (H5D__compound_opt_read(smine_nelmts, mem_iter, &dset_info->type_info, tmp_buf, buf /*out*/) <
571
0
                0)
572
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed");
573
0
        } /* end if */
574
0
        else {
575
            /*
576
             * Perform datatype conversion.
577
             */
578
0
            if (H5T_convert(dset_info->type_info.tpath, dset_info->type_info.src_type,
579
0
                            dset_info->type_info.dst_type, smine_nelmts, (size_t)0, (size_t)0, tmp_buf,
580
0
                            io_info->bkg_buf) < 0)
581
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed");
582
583
            /* Do the data transform after the conversion (since we're using type mem_type) */
584
0
            if (!dset_info->type_info.is_xform_noop) {
585
0
                H5Z_data_xform_t *data_transform; /* Data transform info */
586
587
                /* Retrieve info from API context */
588
0
                if (H5CX_get_data_transform(&data_transform) < 0)
589
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info");
590
591
0
                if (H5Z_xform_eval(data_transform, tmp_buf, smine_nelmts, dset_info->type_info.mem_type) < 0)
592
0
                    HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Error performing data transform");
593
0
            }
594
595
            /* Scatter the data into memory if this was not an in-place conversion */
596
0
            if (!in_place_tconv)
597
0
                if (H5D__scatter_mem(tmp_buf, mem_iter, smine_nelmts, buf /*out*/) < 0)
598
0
                    HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed");
599
0
        } /* end else */
600
0
    }     /* end for */
601
602
0
done:
603
    /* Release selection iterators */
604
0
    if (file_iter_init && H5S_SELECT_ITER_RELEASE(file_iter) < 0)
605
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
606
0
    if (file_iter)
607
0
        file_iter = H5FL_FREE(H5S_sel_iter_t, file_iter);
608
0
    if (mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
609
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
610
0
    if (mem_iter)
611
0
        mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
612
0
    if (bkg_iter_init && H5S_SELECT_ITER_RELEASE(bkg_iter) < 0)
613
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
614
0
    if (bkg_iter)
615
0
        bkg_iter = H5FL_FREE(H5S_sel_iter_t, bkg_iter);
616
617
0
    FUNC_LEAVE_NOAPI(ret_value)
618
0
} /* end H5D__scatgath_read() */
619
620
/*-------------------------------------------------------------------------
621
 * Function:  H5D__scatgath_write
622
 *
623
 * Purpose: Perform scatter/gather write to a contiguous [piece of a] dataset.
624
 *
625
 * Return:  Non-negative on success/Negative on failure
626
 *
627
 *-------------------------------------------------------------------------
628
 */
629
herr_t
630
H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info)
631
0
{
632
0
    const void     *buf;                    /* Local pointer to application buffer */
633
0
    void           *tmp_buf;                /* Buffer to use for type conversion */
634
0
    H5S_sel_iter_t *mem_iter       = NULL;  /* Memory selection iteration info*/
635
0
    bool            mem_iter_init  = false; /* Memory selection iteration info has been initialized */
636
0
    H5S_sel_iter_t *bkg_iter       = NULL;  /* Background iteration info*/
637
0
    bool            bkg_iter_init  = false; /* Background iteration info has been initialized */
638
0
    H5S_sel_iter_t *file_iter      = NULL;  /* File selection iteration info*/
639
0
    bool            file_iter_init = false; /* File selection iteration info has been initialized */
640
0
    hsize_t         smine_start;            /* Strip mine start loc */
641
0
    size_t          smine_nelmts;           /* Elements per strip */
642
0
    bool            in_place_tconv;         /* Whether to perform in-place type_conversion */
643
0
    herr_t          ret_value = SUCCEED;    /* Return value    */
644
645
0
    FUNC_ENTER_PACKAGE
646
647
    /* Sanity check */
648
0
    assert(io_info);
649
0
    assert(dset_info);
650
0
    assert(dset_info->mem_space);
651
0
    assert(dset_info->file_space);
652
0
    assert(dset_info->buf.cvp);
653
654
    /* Set buf pointer */
655
0
    buf = dset_info->buf.cvp;
656
657
    /* Check for NOOP write */
658
0
    if (dset_info->nelmts == 0)
659
0
        HGOTO_DONE(SUCCEED);
660
661
    /* Check for in-place type conversion */
662
0
    in_place_tconv = dset_info->layout_io_info.contig_piece_info &&
663
0
                     dset_info->layout_io_info.contig_piece_info->in_place_tconv;
664
665
    /* Check if we should disable in-place type conversion for performance.  Do so if we can use the optimized
666
     * compound write function, if this is not a selection I/O operation (so we have normal size conversion
667
     * buffers), and the either entire I/O operation can fit in the type conversion buffer or we need to use a
668
     * background buffer (and therefore could not do the I/O in one operation with in-place conversion
669
     * anyways). */
670
0
    if (in_place_tconv && H5D__SCATGATH_USE_CMPD_OPT_WRITE(dset_info, false) &&
671
0
        (io_info->use_select_io != H5D_SELECTION_IO_MODE_ON) &&
672
0
        (dset_info->type_info.need_bkg || (dset_info->nelmts <= dset_info->type_info.request_nelmts)))
673
0
        in_place_tconv = false;
674
675
    /* Allocate the iterators */
676
0
    if (NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
677
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator");
678
0
    if (NULL == (bkg_iter = H5FL_MALLOC(H5S_sel_iter_t)))
679
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate background iterator");
680
0
    if (NULL == (file_iter = H5FL_MALLOC(H5S_sel_iter_t)))
681
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator");
682
683
    /* Figure out the strip mine size. */
684
0
    if (H5S_select_iter_init(file_iter, dset_info->file_space, dset_info->type_info.dst_type_size,
685
0
                             H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0)
686
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information");
687
0
    file_iter_init = true; /*file selection iteration info has been initialized */
688
0
    if (H5S_select_iter_init(mem_iter, dset_info->mem_space, dset_info->type_info.src_type_size, 0) < 0)
689
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information");
690
0
    mem_iter_init = true; /*file selection iteration info has been initialized */
691
0
    if (H5S_select_iter_init(bkg_iter, dset_info->file_space, dset_info->type_info.dst_type_size,
692
0
                             H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0)
693
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information");
694
0
    bkg_iter_init = true; /*file selection iteration info has been initialized */
695
696
    /* Start strip mining... */
697
0
    for (smine_start = 0; smine_start < dset_info->nelmts; smine_start += smine_nelmts) {
698
0
        size_t n; /* Elements operated on */
699
700
0
        assert(H5S_SELECT_ITER_NELMTS(file_iter) == (dset_info->nelmts - smine_start));
701
702
        /* Determine strip mine size. First check if we're doing in-place type conversion */
703
0
        if (in_place_tconv) {
704
            /* If this is not a selection I/O operation and there is a background buffer, we cannot exceed
705
             * request_nelmts.  It could be part of a selection I/O operation if this is used to write the
706
             * fill value to a cached chunk that will immediately be evicted. */
707
0
            assert(!H5D__SCATGATH_USE_CMPD_OPT_WRITE(dset_info, in_place_tconv));
708
0
            if (dset_info->type_info.need_bkg && (io_info->use_select_io != H5D_SELECTION_IO_MODE_ON))
709
0
                smine_nelmts =
710
0
                    (size_t)MIN(dset_info->type_info.request_nelmts, (dset_info->nelmts - smine_start));
711
0
            else {
712
0
                assert(smine_start == 0);
713
0
                smine_nelmts = dset_info->nelmts;
714
0
            }
715
716
            /* Calculate buffer position in user buffer */
717
            /* Use "vp" field of union to twiddle away const.  OK because if we're doing this it means the
718
             * user explicitly allowed us to modify this buffer via H5Pset_modify_write_buf(). */
719
0
            tmp_buf = (uint8_t *)dset_info->buf.vp + dset_info->layout_io_info.contig_piece_info->buf_off +
720
0
                      (smine_start * dset_info->type_info.src_type_size);
721
0
        }
722
0
        else {
723
            /* Do type conversion using intermediate buffer */
724
0
            tmp_buf = io_info->tconv_buf;
725
726
            /* Go figure out how many elements to read from the file */
727
0
            smine_nelmts =
728
0
                (size_t)MIN(dset_info->type_info.request_nelmts, (dset_info->nelmts - smine_start));
729
730
            /*
731
             * Gather data from application buffer into the datatype conversion
732
             * buffer. Also gather data from the file into the background buffer
733
             * if necessary.
734
             */
735
0
            n = H5D__gather_mem(buf, mem_iter, smine_nelmts, tmp_buf /*out*/);
736
0
            if (n != smine_nelmts)
737
0
                HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed");
738
0
        }
739
740
        /* If the source and destination are compound types and the destination is
741
         * is a subset of the source and no conversion is needed, copy the data
742
         * directly from user's buffer and bypass the rest of steps.  If the source
743
         * is a subset of the destination, the optimization is done in conversion
744
         * function H5T_conv_struct_opt to protect the background data.
745
         */
746
0
        if (H5D__SCATGATH_USE_CMPD_OPT_WRITE(dset_info, in_place_tconv)) {
747
0
            if (H5D__compound_opt_write(smine_nelmts, &dset_info->type_info, tmp_buf) < 0)
748
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed");
749
750
0
        } /* end if */
751
0
        else {
752
0
            if (H5T_BKG_YES == dset_info->type_info.need_bkg) {
753
0
                n = H5D__gather_file(io_info, dset_info, bkg_iter, smine_nelmts, io_info->bkg_buf /*out*/);
754
0
                if (n != smine_nelmts)
755
0
                    HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed");
756
0
            } /* end if */
757
758
            /* Do the data transform before the type conversion (since
759
             * transforms must be done in the memory type). */
760
0
            if (!dset_info->type_info.is_xform_noop) {
761
0
                H5Z_data_xform_t *data_transform; /* Data transform info */
762
763
                /* Retrieve info from API context */
764
0
                if (H5CX_get_data_transform(&data_transform) < 0)
765
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info");
766
767
0
                if (H5Z_xform_eval(data_transform, tmp_buf, smine_nelmts, dset_info->type_info.mem_type) < 0)
768
0
                    HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Error performing data transform");
769
0
            }
770
771
            /*
772
             * Perform datatype conversion.
773
             */
774
0
            if (H5T_convert(dset_info->type_info.tpath, dset_info->type_info.src_type,
775
0
                            dset_info->type_info.dst_type, smine_nelmts, (size_t)0, (size_t)0, tmp_buf,
776
0
                            io_info->bkg_buf) < 0)
777
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed");
778
0
        } /* end else */
779
780
        /*
781
         * Scatter the data out to the file.
782
         */
783
0
        if (H5D__scatter_file(io_info, dset_info, file_iter, smine_nelmts, tmp_buf) < 0)
784
0
            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed");
785
0
    } /* end for */
786
787
0
done:
788
    /* Release selection iterators */
789
0
    if (file_iter_init && H5S_SELECT_ITER_RELEASE(file_iter) < 0)
790
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
791
0
    if (file_iter)
792
0
        file_iter = H5FL_FREE(H5S_sel_iter_t, file_iter);
793
0
    if (mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
794
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
795
0
    if (mem_iter)
796
0
        mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
797
0
    if (bkg_iter_init && H5S_SELECT_ITER_RELEASE(bkg_iter) < 0)
798
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
799
0
    if (bkg_iter)
800
0
        bkg_iter = H5FL_FREE(H5S_sel_iter_t, bkg_iter);
801
802
0
    FUNC_LEAVE_NOAPI(ret_value)
803
0
} /* end H5D__scatgath_write() */
804
805
/*-------------------------------------------------------------------------
806
 * Function:  H5D__scatgath_read_select
807
 *
808
 * Purpose: Perform scatter/gather read from a list of dataset pieces
809
 *
810
 * Return:  Non-negative on success/Negative on failure
811
 *
812
 *-------------------------------------------------------------------------
813
 */
814
herr_t
815
H5D__scatgath_read_select(H5D_io_info_t *io_info)
816
0
{
817
0
    H5S_t         **tmp_mem_spaces   = NULL;  /* Memory spaces to use for read from disk */
818
0
    H5S_sel_iter_t *mem_iter         = NULL;  /* Memory selection iteration info */
819
0
    bool            mem_iter_init    = false; /* Memory selection iteration info has been initialized */
820
0
    void          **tmp_bufs         = NULL;  /* Buffers to use for read from disk */
821
0
    void           *tmp_bkg_buf      = NULL;  /* Temporary background buffer pointer */
822
0
    size_t          tconv_bytes_used = 0;     /* Number of bytes used so far in conversion buffer */
823
0
    size_t          bkg_bytes_used   = 0;     /* Number of bytes used so far in background buffer */
824
0
    size_t          i;                        /* Local index variable */
825
0
    herr_t          ret_value = SUCCEED;      /* Return value    */
826
827
0
    FUNC_ENTER_PACKAGE
828
829
    /* Sanity check */
830
0
    assert(io_info);
831
0
    assert(io_info->count > 0);
832
0
    assert(io_info->mem_spaces || io_info->pieces_added == 0);
833
0
    assert(io_info->file_spaces || io_info->pieces_added == 0);
834
0
    assert(io_info->addrs || io_info->pieces_added == 0);
835
0
    assert(io_info->element_sizes || io_info->pieces_added == 0);
836
0
    assert(io_info->rbufs || io_info->pieces_added == 0);
837
838
    /* Allocate list of buffers (within the tconv buf) */
839
0
    if (NULL == (tmp_bufs = H5MM_malloc(io_info->pieces_added * sizeof(void *))))
840
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for temporary buffer list");
841
842
    /* Allocate the iterator */
843
0
    if (NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
844
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator");
845
846
    /* Allocate list of block memory spaces */
847
    /*!FIXME delay doing this until we find the first mem space that is non-contiguous or doesn't start at 0
848
     */
849
0
    if (NULL == (tmp_mem_spaces = H5MM_malloc(io_info->pieces_added * sizeof(H5S_t *))))
850
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
851
0
                    "memory allocation failed for temporary memory space list");
852
853
    /* Build read operation to tconv buffer */
854
0
    for (i = 0; i < io_info->pieces_added; i++) {
855
0
        H5D_dset_io_info_t *dset_info = io_info->sel_pieces[i]->dset_info;
856
857
0
        assert(io_info->sel_pieces[i]->piece_points > 0);
858
859
        /* Check if this piece is involved in type conversion */
860
0
        if (dset_info->type_info.is_xform_noop && dset_info->type_info.is_conv_noop) {
861
            /* No type conversion, just copy the mem space and buffer */
862
0
            tmp_mem_spaces[i] = io_info->mem_spaces[i];
863
0
            tmp_bufs[i]       = io_info->rbufs[i];
864
0
        }
865
0
        else {
866
            /* Create block memory space */
867
0
            if (NULL ==
868
0
                (tmp_mem_spaces[i] = H5S_create_simple(1, &io_info->sel_pieces[i]->piece_points, NULL))) {
869
0
                memset(&tmp_mem_spaces[i], 0, (io_info->pieces_added - i) * sizeof(tmp_mem_spaces[0]));
870
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "unable to create simple memory dataspace");
871
0
            }
872
873
            /* Check for in-place type conversion */
874
0
            if (io_info->sel_pieces[i]->in_place_tconv)
875
                /* Set buffer to point to read buffer + offset */
876
0
                tmp_bufs[i] = (uint8_t *)(io_info->rbufs[i]) + io_info->sel_pieces[i]->buf_off;
877
0
            else {
878
                /* Set buffer to point into type conversion buffer */
879
0
                tmp_bufs[i] = io_info->tconv_buf + tconv_bytes_used;
880
0
                tconv_bytes_used +=
881
0
                    io_info->sel_pieces[i]->piece_points *
882
0
                    MAX(dset_info->type_info.src_type_size, dset_info->type_info.dst_type_size);
883
0
                assert(tconv_bytes_used <= io_info->tconv_buf_size);
884
0
            }
885
886
            /* Fill background buffer here unless we will use H5D__compound_opt_read().  Must do this before
887
             * the read so the read buffer doesn't get wiped out if we're using in-place type conversion */
888
0
            if (!H5D__SCATGATH_USE_CMPD_OPT_READ(dset_info, io_info->sel_pieces[i]->in_place_tconv)) {
889
                /* Check for background buffer */
890
0
                if (dset_info->type_info.need_bkg) {
891
0
                    assert(io_info->bkg_buf);
892
893
                    /* Calculate background buffer position */
894
0
                    tmp_bkg_buf = io_info->bkg_buf + bkg_bytes_used;
895
0
                    bkg_bytes_used +=
896
0
                        io_info->sel_pieces[i]->piece_points * dset_info->type_info.dst_type_size;
897
0
                    assert(bkg_bytes_used <= io_info->bkg_buf_size);
898
899
                    /* Gather data from read buffer to background buffer if necessary */
900
0
                    if (H5T_BKG_YES == dset_info->type_info.need_bkg) {
901
                        /* Initialize memory iterator */
902
0
                        assert(!mem_iter_init);
903
0
                        if (H5S_select_iter_init(mem_iter, io_info->mem_spaces[i],
904
0
                                                 dset_info->type_info.dst_type_size, 0) < 0)
905
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL,
906
0
                                        "unable to initialize memory selection information");
907
0
                        mem_iter_init = true; /* Memory selection iteration info has been initialized */
908
909
0
                        if ((size_t)io_info->sel_pieces[i]->piece_points !=
910
0
                            H5D__gather_mem(io_info->rbufs[i], mem_iter,
911
0
                                            (size_t)io_info->sel_pieces[i]->piece_points,
912
0
                                            tmp_bkg_buf /*out*/))
913
0
                            HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed");
914
915
                        /* Reset selection iterator */
916
0
                        assert(mem_iter_init);
917
0
                        if (H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
918
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
919
0
                        mem_iter_init = false;
920
0
                    }
921
0
                }
922
0
            }
923
0
        }
924
0
    }
925
926
    /* Read data from all pieces */
927
0
    H5_CHECK_OVERFLOW(io_info->pieces_added, size_t, uint32_t);
928
0
    if (H5F_shared_select_read(io_info->f_sh, H5FD_MEM_DRAW, (uint32_t)io_info->pieces_added, tmp_mem_spaces,
929
0
                               io_info->file_spaces, io_info->addrs, io_info->element_sizes, tmp_bufs) < 0)
930
0
        HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "selection read failed");
931
932
    /* Reset bkg_bytes_used */
933
0
    bkg_bytes_used = 0;
934
935
    /* Perform type conversion and scatter data to memory buffers for datasets that need this */
936
0
    for (i = 0; i < io_info->pieces_added; i++) {
937
0
        H5D_dset_io_info_t *dset_info = io_info->sel_pieces[i]->dset_info;
938
939
0
        assert(tmp_mem_spaces[i]);
940
941
        /* Check if this piece is involved in type conversion */
942
0
        if (tmp_mem_spaces[i] != io_info->mem_spaces[i]) {
943
0
            H5_CHECK_OVERFLOW(io_info->sel_pieces[i]->piece_points, hsize_t, size_t);
944
945
            /* Initialize memory iterator */
946
0
            assert(!mem_iter_init);
947
0
            if (H5S_select_iter_init(mem_iter, io_info->mem_spaces[i], dset_info->type_info.dst_type_size,
948
0
                                     0) < 0)
949
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL,
950
0
                            "unable to initialize memory selection information");
951
0
            mem_iter_init = true; /* Memory selection iteration info has been initialized */
952
953
            /* If the source and destination are compound types and subset of each other
954
             * and no conversion is needed, copy the data directly into user's buffer and
955
             * bypass the rest of steps.
956
             */
957
0
            if (H5D__SCATGATH_USE_CMPD_OPT_READ(dset_info, io_info->sel_pieces[i]->in_place_tconv)) {
958
0
                if (H5D__compound_opt_read((size_t)io_info->sel_pieces[i]->piece_points, mem_iter,
959
0
                                           &dset_info->type_info, tmp_bufs[i], io_info->rbufs[i] /*out*/) < 0)
960
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed");
961
0
            }
962
0
            else {
963
                /* Check for background buffer */
964
0
                if (dset_info->type_info.need_bkg) {
965
0
                    assert(io_info->bkg_buf);
966
967
                    /* Calculate background buffer position */
968
0
                    tmp_bkg_buf = io_info->bkg_buf + bkg_bytes_used;
969
0
                    bkg_bytes_used +=
970
0
                        io_info->sel_pieces[i]->piece_points * dset_info->type_info.dst_type_size;
971
0
                    assert(bkg_bytes_used <= io_info->bkg_buf_size);
972
0
                }
973
974
                /*
975
                 * Perform datatype conversion.
976
                 */
977
0
                if (H5T_convert(dset_info->type_info.tpath, dset_info->type_info.src_type,
978
0
                                dset_info->type_info.dst_type, (size_t)io_info->sel_pieces[i]->piece_points,
979
0
                                (size_t)0, (size_t)0, tmp_bufs[i], tmp_bkg_buf) < 0)
980
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed");
981
982
                /* Do the data transform after the conversion (since we're using type mem_type) */
983
0
                if (!dset_info->type_info.is_xform_noop) {
984
0
                    H5Z_data_xform_t *data_transform; /* Data transform info */
985
986
                    /* Retrieve info from API context */
987
0
                    if (H5CX_get_data_transform(&data_transform) < 0)
988
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info");
989
990
0
                    if (H5Z_xform_eval(data_transform, tmp_bufs[i],
991
0
                                       (size_t)io_info->sel_pieces[i]->piece_points,
992
0
                                       dset_info->type_info.mem_type) < 0)
993
0
                        HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Error performing data transform");
994
0
                }
995
996
                /* Scatter the data into memory if this was not an in-place conversion */
997
0
                if (!io_info->sel_pieces[i]->in_place_tconv)
998
0
                    if (H5D__scatter_mem(tmp_bufs[i], mem_iter, (size_t)io_info->sel_pieces[i]->piece_points,
999
0
                                         io_info->rbufs[i] /*out*/) < 0)
1000
0
                        HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed");
1001
0
            }
1002
1003
            /* Release selection iterator */
1004
0
            assert(mem_iter_init);
1005
0
            if (H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
1006
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
1007
0
            mem_iter_init = false;
1008
0
        }
1009
0
    }
1010
1011
0
done:
1012
    /* Release and free selection iterator */
1013
0
    if (mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
1014
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
1015
0
    if (mem_iter)
1016
0
        mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
1017
1018
    /* Free tmp_bufs */
1019
0
    H5MM_free(tmp_bufs);
1020
0
    tmp_bufs = NULL;
1021
1022
    /* Clear and free tmp_mem_spaces */
1023
0
    if (tmp_mem_spaces) {
1024
0
        for (i = 0; i < io_info->pieces_added; i++)
1025
0
            if (tmp_mem_spaces[i] != io_info->mem_spaces[i] && tmp_mem_spaces[i] &&
1026
0
                H5S_close(tmp_mem_spaces[i]) < 0)
1027
0
                HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "Can't close dataspace");
1028
0
        H5MM_free(tmp_mem_spaces);
1029
0
        tmp_mem_spaces = NULL;
1030
0
    }
1031
1032
0
    FUNC_LEAVE_NOAPI(ret_value)
1033
0
} /* end H5D__scatgath_read_select() */
1034
1035
/*-------------------------------------------------------------------------
1036
 * Function:  H5D__scatgath_write_select
1037
 *
1038
 * Purpose: Perform scatter/gather write to a list of dataset pieces.
1039
 *
1040
 * Return:  Non-negative on success/Negative on failure
1041
 *
1042
 *-------------------------------------------------------------------------
1043
 */
1044
herr_t
1045
H5D__scatgath_write_select(H5D_io_info_t *io_info)
1046
0
{
1047
0
    H5S_t         **write_mem_spaces  = NULL;  /* Memory spaces to use for write to disk */
1048
0
    size_t          spaces_added      = 0;     /* Number of spaces added to write_mem_spaces */
1049
0
    H5S_sel_iter_t *mem_iter          = NULL;  /* Memory selection iteration info */
1050
0
    bool            mem_iter_init     = false; /* Memory selection iteration info has been initialized */
1051
0
    const void    **write_bufs        = NULL;  /* Buffers to use for write to disk */
1052
0
    size_t          tconv_bytes_used  = 0;     /* Number of bytes used so far in conversion buffer */
1053
0
    size_t          bkg_bytes_used    = 0;     /* Number of bytes used so far in background buffer */
1054
0
    H5S_t         **bkg_mem_spaces    = NULL;  /* Array of memory spaces for read to background buffer */
1055
0
    H5S_t         **bkg_file_spaces   = NULL;  /* Array of file spaces for read to background buffer */
1056
0
    haddr_t        *bkg_addrs         = NULL;  /* Array of file addresses for read to background buffer */
1057
0
    size_t         *bkg_element_sizes = NULL;  /* Array of element sizes for read to background buffer */
1058
0
    void          **bkg_bufs   = NULL; /* Array background buffers for read of existing file contents */
1059
0
    size_t          bkg_pieces = 0;    /* Number of pieces that need to read the background data from disk */
1060
0
    size_t          i;                 /* Local index variable */
1061
0
    herr_t          ret_value = SUCCEED; /* Return value   */
1062
1063
0
    FUNC_ENTER_PACKAGE
1064
1065
    /* Sanity check */
1066
0
    assert(io_info);
1067
0
    assert(io_info->count > 0);
1068
0
    assert(io_info->mem_spaces || io_info->pieces_added == 0);
1069
0
    assert(io_info->file_spaces || io_info->pieces_added == 0);
1070
0
    assert(io_info->addrs || io_info->pieces_added == 0);
1071
0
    assert(io_info->element_sizes || io_info->pieces_added == 0);
1072
0
    assert(io_info->wbufs || io_info->pieces_added == 0);
1073
1074
    /* Allocate list of buffers (within the tconv buf) */
1075
0
    if (NULL == (write_bufs = (const void **)H5MM_malloc(io_info->pieces_added * sizeof(const void *))))
1076
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "memory allocation failed for temporary buffer list");
1077
1078
    /* Allocate the iterator */
1079
0
    if (NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
1080
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator");
1081
1082
    /* Allocate list of block memory spaces */
1083
    /*!FIXME delay doing this until we find the first mem space that is non-contiguous or doesn't start at 0
1084
     */
1085
0
    if (NULL == (write_mem_spaces = H5MM_malloc(io_info->pieces_added * sizeof(H5S_t *))))
1086
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
1087
0
                    "memory allocation failed for temporary memory space list");
1088
1089
    /* Build operations to read data to background buffer and to write data */
1090
0
    for (i = 0; i < io_info->pieces_added; i++) {
1091
0
        H5D_dset_io_info_t *dset_info = io_info->sel_pieces[i]->dset_info;
1092
1093
0
        assert(io_info->sel_pieces[i]->piece_points > 0);
1094
1095
        /* Check if this piece is involved in type conversion */
1096
0
        if (dset_info->type_info.is_xform_noop && dset_info->type_info.is_conv_noop) {
1097
            /* No type conversion, just copy the mem space and buffer */
1098
0
            write_mem_spaces[i] = io_info->mem_spaces[i];
1099
0
            spaces_added++;
1100
0
            write_bufs[i] = io_info->wbufs[i];
1101
0
        }
1102
0
        else {
1103
0
            void *tmp_write_buf; /* To sidestep const warnings */
1104
0
            void *tmp_bkg_buf = NULL;
1105
1106
0
            H5_CHECK_OVERFLOW(io_info->sel_pieces[i]->piece_points, hsize_t, size_t);
1107
1108
            /* Initialize memory iterator */
1109
0
            assert(!mem_iter_init);
1110
0
            if (H5S_select_iter_init(mem_iter, io_info->mem_spaces[i], dset_info->type_info.src_type_size,
1111
0
                                     0) < 0)
1112
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL,
1113
0
                            "unable to initialize memory selection information");
1114
0
            mem_iter_init = true; /* Memory selection iteration info has been initialized */
1115
1116
            /* Create block memory space */
1117
0
            if (NULL ==
1118
0
                (write_mem_spaces[i] = H5S_create_simple(1, &io_info->sel_pieces[i]->piece_points, NULL)))
1119
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "unable to create simple memory dataspace");
1120
0
            spaces_added++;
1121
1122
            /* Check for in-place type conversion */
1123
0
            if (io_info->sel_pieces[i]->in_place_tconv) {
1124
0
                H5_flexible_const_ptr_t flex_buf;
1125
1126
                /* Set buffer to point to write buffer + offset */
1127
                /* Use cast to union to twiddle away const.  OK because if we're doing this it means the user
1128
                 * explicitly allowed us to modify this buffer via H5Pset_modify_write_buf(). */
1129
0
                flex_buf.cvp  = io_info->wbufs[i];
1130
0
                tmp_write_buf = (uint8_t *)flex_buf.vp + io_info->sel_pieces[i]->buf_off;
1131
0
            }
1132
0
            else {
1133
                /* Set buffer to point into type conversion buffer */
1134
0
                tmp_write_buf = io_info->tconv_buf + tconv_bytes_used;
1135
0
                tconv_bytes_used +=
1136
0
                    io_info->sel_pieces[i]->piece_points *
1137
0
                    MAX(dset_info->type_info.src_type_size, dset_info->type_info.dst_type_size);
1138
0
                assert(tconv_bytes_used <= io_info->tconv_buf_size);
1139
1140
                /* Gather data from application buffer into the datatype conversion buffer */
1141
0
                if ((size_t)io_info->sel_pieces[i]->piece_points !=
1142
0
                    H5D__gather_mem(io_info->wbufs[i], mem_iter, (size_t)io_info->sel_pieces[i]->piece_points,
1143
0
                                    tmp_write_buf /*out*/))
1144
0
                    HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed");
1145
0
            }
1146
1147
            /* Set buffer for writing to disk (from type conversion buffer) */
1148
0
            write_bufs[i] = (const void *)tmp_write_buf;
1149
1150
            /* If the source and destination are compound types and the destination is a subset of
1151
             * the source and no conversion is needed, copy the data directly into the type
1152
             * conversion buffer and bypass the rest of steps.  If the source is a subset of the
1153
             * destination, the optimization is done in conversion function H5T_conv_struct_opt to
1154
             * protect the background data.
1155
             */
1156
0
            if (H5D__SCATGATH_USE_CMPD_OPT_WRITE(dset_info, io_info->sel_pieces[i]->in_place_tconv)) {
1157
0
                if (H5D__compound_opt_write((size_t)io_info->sel_pieces[i]->piece_points,
1158
0
                                            &dset_info->type_info, tmp_write_buf) < 0)
1159
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed");
1160
1161
0
            } /* end if */
1162
0
            else {
1163
                /* Check for background buffer */
1164
0
                if (dset_info->type_info.need_bkg) {
1165
0
                    assert(io_info->bkg_buf);
1166
1167
                    /* Calculate background buffer position */
1168
0
                    tmp_bkg_buf = io_info->bkg_buf + bkg_bytes_used;
1169
0
                    bkg_bytes_used +=
1170
0
                        io_info->sel_pieces[i]->piece_points * dset_info->type_info.dst_type_size;
1171
0
                    assert(bkg_bytes_used <= io_info->bkg_buf_size);
1172
0
                }
1173
1174
                /* Set up background buffer read operation if necessary */
1175
0
                if (H5T_BKG_YES == dset_info->type_info.need_bkg) {
1176
0
                    assert(io_info->must_fill_bkg);
1177
1178
                    /* Allocate arrays of parameters for selection read to background buffer if necessary */
1179
0
                    if (!bkg_mem_spaces) {
1180
0
                        assert(!bkg_file_spaces && !bkg_addrs && !bkg_element_sizes && !bkg_bufs);
1181
0
                        if (NULL == (bkg_mem_spaces = H5MM_malloc(io_info->pieces_added * sizeof(H5S_t *))))
1182
0
                            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
1183
0
                                        "memory allocation failed for memory space list");
1184
0
                        if (NULL == (bkg_file_spaces = H5MM_malloc(io_info->pieces_added * sizeof(H5S_t *))))
1185
0
                            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
1186
0
                                        "memory allocation failed for file space list");
1187
0
                        if (NULL == (bkg_addrs = H5MM_malloc(io_info->pieces_added * sizeof(haddr_t))))
1188
0
                            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
1189
0
                                        "memory allocation failed for piece address list");
1190
0
                        if (NULL == (bkg_element_sizes = H5MM_malloc(io_info->pieces_added * sizeof(size_t))))
1191
0
                            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
1192
0
                                        "memory allocation failed for element size list");
1193
0
                        if (NULL == (bkg_bufs = H5MM_malloc(io_info->pieces_added * sizeof(const void *))))
1194
0
                            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
1195
0
                                        "memory allocation failed for write buffer list");
1196
0
                    }
1197
1198
                    /* Use same (block) memory space, file space, address, and element size as write operation
1199
                     */
1200
0
                    assert(bkg_mem_spaces && bkg_file_spaces && bkg_addrs && bkg_element_sizes && bkg_bufs);
1201
0
                    bkg_mem_spaces[bkg_pieces]    = write_mem_spaces[i];
1202
0
                    bkg_file_spaces[bkg_pieces]   = io_info->file_spaces[i];
1203
0
                    bkg_addrs[bkg_pieces]         = io_info->addrs[i];
1204
0
                    bkg_element_sizes[bkg_pieces] = io_info->element_sizes[i];
1205
1206
                    /* Use previously calculated background buffer position */
1207
0
                    bkg_bufs[bkg_pieces] = tmp_bkg_buf;
1208
1209
                    /* Add piece */
1210
0
                    bkg_pieces++;
1211
0
                }
1212
0
                else {
1213
                    /* Perform type conversion here to avoid second loop if no dsets use the background buffer
1214
                     */
1215
                    /* Do the data transform before the type conversion (since
1216
                     * transforms must be done in the memory type). */
1217
0
                    if (!dset_info->type_info.is_xform_noop) {
1218
0
                        H5Z_data_xform_t *data_transform; /* Data transform info */
1219
1220
                        /* Retrieve info from API context */
1221
0
                        if (H5CX_get_data_transform(&data_transform) < 0)
1222
0
                            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info");
1223
1224
0
                        if (H5Z_xform_eval(data_transform, tmp_write_buf,
1225
0
                                           (size_t)io_info->sel_pieces[i]->piece_points,
1226
0
                                           dset_info->type_info.mem_type) < 0)
1227
0
                            HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Error performing data transform");
1228
0
                    }
1229
1230
                    /*
1231
                     * Perform datatype conversion.
1232
                     */
1233
0
                    if (H5T_convert(dset_info->type_info.tpath, dset_info->type_info.src_type,
1234
0
                                    dset_info->type_info.dst_type,
1235
0
                                    (size_t)io_info->sel_pieces[i]->piece_points, (size_t)0, (size_t)0,
1236
0
                                    tmp_write_buf, tmp_bkg_buf) < 0)
1237
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed");
1238
0
                }
1239
0
            }
1240
1241
            /* Release selection iterator */
1242
0
            assert(mem_iter_init);
1243
0
            if (H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
1244
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
1245
0
            mem_iter_init = false;
1246
0
        }
1247
0
    }
1248
1249
0
    assert(spaces_added == io_info->pieces_added);
1250
1251
    /* Gather data to background buffer if necessary */
1252
0
    if (io_info->must_fill_bkg) {
1253
0
        size_t j = 0; /* Index into array of background buffers */
1254
1255
        /* Read data */
1256
0
        H5_CHECK_OVERFLOW(bkg_pieces, size_t, uint32_t);
1257
0
        if (H5F_shared_select_read(io_info->f_sh, H5FD_MEM_DRAW, (uint32_t)bkg_pieces, bkg_mem_spaces,
1258
0
                                   bkg_file_spaces, bkg_addrs, bkg_element_sizes, bkg_bufs) < 0)
1259
0
            HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "selection read to background buffer failed");
1260
1261
        /* Perform type conversion on pieces with background buffers that were just read */
1262
0
        for (i = 0; i < io_info->pieces_added; i++) {
1263
0
            H5D_dset_io_info_t *dset_info = io_info->sel_pieces[i]->dset_info;
1264
1265
0
            if ((H5T_BKG_YES == dset_info->type_info.need_bkg) &&
1266
0
                !H5D__SCATGATH_USE_CMPD_OPT_WRITE(dset_info, io_info->sel_pieces[i]->in_place_tconv)) {
1267
                /* Non-const write_buf[i].  Use pointer math here to avoid const warnings.  When
1268
                 * there's a background buffer write_buf[i] always points inside the non-const tconv
1269
                 * buf so this is OK. */
1270
0
                void *tmp_write_buf =
1271
0
                    (void *)((uint8_t *)io_info->tconv_buf +
1272
0
                             ((const uint8_t *)write_bufs[i] - (const uint8_t *)io_info->tconv_buf));
1273
1274
                /* Do the data transform before the type conversion (since
1275
                 * transforms must be done in the memory type). */
1276
0
                if (!dset_info->type_info.is_xform_noop) {
1277
0
                    H5Z_data_xform_t *data_transform; /* Data transform info */
1278
1279
                    /* Retrieve info from API context */
1280
0
                    if (H5CX_get_data_transform(&data_transform) < 0)
1281
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info");
1282
1283
0
                    if (H5Z_xform_eval(data_transform, tmp_write_buf,
1284
0
                                       (size_t)io_info->sel_pieces[i]->piece_points,
1285
0
                                       dset_info->type_info.mem_type) < 0)
1286
0
                        HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Error performing data transform");
1287
0
                }
1288
1289
                /*
1290
                 * Perform datatype conversion.
1291
                 */
1292
0
                assert(j < bkg_pieces);
1293
0
                if (H5T_convert(dset_info->type_info.tpath, dset_info->type_info.src_type,
1294
0
                                dset_info->type_info.dst_type, (size_t)io_info->sel_pieces[i]->piece_points,
1295
0
                                (size_t)0, (size_t)0, tmp_write_buf, bkg_bufs[j]) < 0)
1296
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed");
1297
1298
                /* Advance to next background buffer */
1299
0
                j++;
1300
0
            }
1301
0
        }
1302
1303
0
        assert(j == bkg_pieces);
1304
0
    }
1305
1306
    /* Write data to disk */
1307
0
    H5_CHECK_OVERFLOW(io_info->pieces_added, size_t, uint32_t);
1308
0
    if (H5F_shared_select_write(io_info->f_sh, H5FD_MEM_DRAW, (uint32_t)io_info->pieces_added,
1309
0
                                write_mem_spaces, io_info->file_spaces, io_info->addrs,
1310
0
                                io_info->element_sizes, write_bufs) < 0)
1311
0
        HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "selection write failed");
1312
1313
0
done:
1314
    /* Release and free selection iterator */
1315
0
    if (mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
1316
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator");
1317
0
    if (mem_iter)
1318
0
        mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
1319
1320
    /* Free write_bufs */
1321
0
    H5MM_free(write_bufs);
1322
0
    write_bufs = NULL;
1323
1324
    /* Clear and free write_mem_spaces */
1325
0
    if (write_mem_spaces) {
1326
0
        for (i = 0; i < spaces_added; i++) {
1327
0
            assert(write_mem_spaces[i]);
1328
0
            if (write_mem_spaces[i] != io_info->mem_spaces[i] && H5S_close(write_mem_spaces[i]) < 0)
1329
0
                HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "Can't close dataspace");
1330
0
        }
1331
0
        H5MM_free(write_mem_spaces);
1332
0
        write_mem_spaces = NULL;
1333
0
    }
1334
1335
    /* Free background buffer parameter arrays */
1336
0
    H5MM_free(bkg_mem_spaces);
1337
0
    bkg_mem_spaces = NULL;
1338
0
    H5MM_free(bkg_file_spaces);
1339
0
    bkg_file_spaces = NULL;
1340
0
    H5MM_free(bkg_addrs);
1341
0
    bkg_addrs = NULL;
1342
0
    H5MM_free(bkg_element_sizes);
1343
0
    bkg_element_sizes = NULL;
1344
0
    H5MM_free(bkg_bufs);
1345
0
    bkg_bufs = NULL;
1346
1347
0
    FUNC_LEAVE_NOAPI(ret_value)
1348
0
} /* end H5D__scatgath_write_select() */
1349
1350
/*-------------------------------------------------------------------------
1351
 * Function:  H5D__compound_opt_read
1352
 *
1353
 * Purpose: A special optimization case when the source and
1354
 *              destination members are a subset of each other, and
1355
 *              the order is the same, and no conversion is needed.
1356
 *              For example:
1357
 *                  struct source {            struct destination {
1358
 *                      TYPE1 A;      -->          TYPE1 A;
1359
 *                      TYPE2 B;      -->          TYPE2 B;
1360
 *                      TYPE3 C;      -->          TYPE3 C;
1361
 *                  };                             TYPE4 D;
1362
 *                                                 TYPE5 E;
1363
 *                                             };
1364
 *              or
1365
 *                  struct destination {       struct source {
1366
 *                      TYPE1 A;      <--          TYPE1 A;
1367
 *                      TYPE2 B;      <--          TYPE2 B;
1368
 *                      TYPE3 C;      <--          TYPE3 C;
1369
 *                  };                             TYPE4 D;
1370
 *                                                 TYPE5 E;
1371
 *                                             };
1372
 *              The optimization is simply moving data to the appropriate
1373
 *              places in the buffer.
1374
 *
1375
 * Return:  Non-negative on success/Negative on failure
1376
 *
1377
 *-------------------------------------------------------------------------
1378
 */
1379
static herr_t
1380
H5D__compound_opt_read(size_t nelmts, H5S_sel_iter_t *iter, const H5D_type_info_t *type_info,
1381
                       uint8_t *tconv_buf, void *user_buf /*out*/)
1382
0
{
1383
0
    uint8_t *ubuf = (uint8_t *)user_buf; /* Cast for pointer arithmetic */
1384
0
    uint8_t *xdbuf;                      /* Pointer into dataset buffer */
1385
0
    hsize_t *off = NULL;                 /* Pointer to sequence offsets */
1386
0
    size_t  *len = NULL;                 /* Pointer to sequence lengths */
1387
0
    size_t   src_stride, dst_stride, copy_size;
1388
0
    size_t   dxpl_vec_size;       /* Vector length from API context's DXPL */
1389
0
    size_t   vec_size;            /* Vector length */
1390
0
    herr_t   ret_value = SUCCEED; /* Return value   */
1391
1392
0
    FUNC_ENTER_PACKAGE
1393
1394
    /* Check args */
1395
0
    assert(nelmts > 0);
1396
0
    assert(iter);
1397
0
    assert(type_info);
1398
0
    assert(type_info->cmpd_subset);
1399
0
    assert(H5T_SUBSET_SRC == type_info->cmpd_subset->subset ||
1400
0
           H5T_SUBSET_DST == type_info->cmpd_subset->subset);
1401
0
    assert(user_buf);
1402
1403
    /* Get info from API context */
1404
0
    if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
1405
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve I/O vector size");
1406
1407
    /* Allocate the vector I/O arrays */
1408
0
    if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
1409
0
        vec_size = dxpl_vec_size;
1410
0
    else
1411
0
        vec_size = H5D_IO_VECTOR_SIZE;
1412
0
    if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
1413
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array");
1414
0
    if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
1415
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array");
1416
1417
    /* Get source & destination strides */
1418
0
    src_stride = type_info->src_type_size;
1419
0
    dst_stride = type_info->dst_type_size;
1420
1421
    /* Get the size, in bytes, to copy for each element */
1422
0
    copy_size = type_info->cmpd_subset->copy_size;
1423
1424
    /* Loop until all elements are written */
1425
0
    xdbuf = tconv_buf;
1426
0
    while (nelmts > 0) {
1427
0
        size_t nseq;     /* Number of sequences generated */
1428
0
        size_t curr_seq; /* Current sequence being processed */
1429
0
        size_t elmtno;   /* Element counter */
1430
1431
        /* Get list of sequences for selection to write */
1432
0
        if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &elmtno, off, len) < 0)
1433
0
            HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed");
1434
1435
        /* Loop, while sequences left to process */
1436
0
        for (curr_seq = 0; curr_seq < nseq; curr_seq++) {
1437
0
            size_t   curr_off;    /* Offset of bytes left to process in sequence */
1438
0
            size_t   curr_len;    /* Length of bytes left to process in sequence */
1439
0
            size_t   curr_nelmts; /* Number of elements to process in sequence   */
1440
0
            uint8_t *xubuf;
1441
0
            size_t   i; /* Local index variable */
1442
1443
            /* Get the number of bytes and offset in sequence */
1444
0
            curr_len = len[curr_seq];
1445
0
            H5_CHECK_OVERFLOW(off[curr_seq], hsize_t, size_t);
1446
0
            curr_off = (size_t)off[curr_seq];
1447
1448
            /* Decide the number of elements and position in the buffer. */
1449
0
            curr_nelmts = curr_len / dst_stride;
1450
0
            xubuf       = ubuf + curr_off;
1451
1452
            /* Copy the data into the right place. */
1453
0
            for (i = 0; i < curr_nelmts; i++) {
1454
0
                memmove(xubuf, xdbuf, copy_size);
1455
1456
                /* Update pointers */
1457
0
                xdbuf += src_stride;
1458
0
                xubuf += dst_stride;
1459
0
            } /* end for */
1460
0
        }     /* end for */
1461
1462
        /* Decrement number of elements left to process */
1463
0
        nelmts -= elmtno;
1464
0
    } /* end while */
1465
1466
0
done:
1467
    /* Release resources, if allocated */
1468
0
    if (len)
1469
0
        len = H5FL_SEQ_FREE(size_t, len);
1470
0
    if (off)
1471
0
        off = H5FL_SEQ_FREE(hsize_t, off);
1472
1473
0
    FUNC_LEAVE_NOAPI(ret_value)
1474
0
} /* end H5D__compound_opt_read() */
1475
1476
/*-------------------------------------------------------------------------
1477
 * Function:  H5D__compound_opt_write
1478
 *
1479
 * Purpose: A special optimization case when the source and
1480
 *              destination members are a subset of each other, and
1481
 *              the order is the same, and no conversion is needed.
1482
 *              For example:
1483
 *                  struct source {            struct destination {
1484
 *                      TYPE1 A;      -->          TYPE1 A;
1485
 *                      TYPE2 B;      -->          TYPE2 B;
1486
 *                      TYPE3 C;      -->          TYPE3 C;
1487
 *                  };                             TYPE4 D;
1488
 *                                                 TYPE5 E;
1489
 *                                             };
1490
 *              or
1491
 *                  struct destination {       struct source {
1492
 *                      TYPE1 A;      <--          TYPE1 A;
1493
 *                      TYPE2 B;      <--          TYPE2 B;
1494
 *                      TYPE3 C;      <--          TYPE3 C;
1495
 *                  };                             TYPE4 D;
1496
 *                                                 TYPE5 E;
1497
 *                                             };
1498
 *              The optimization is simply moving data to the appropriate
1499
 *              places in the buffer.
1500
 *
1501
 *
1502
 * Return:  Non-negative on success/Negative on failure
1503
 *
1504
 *-------------------------------------------------------------------------
1505
 */
1506
static herr_t
1507
H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info, void *tconv_buf)
1508
0
{
1509
0
    uint8_t *xsbuf, *xdbuf;          /* Source & destination pointers into dataset buffer */
1510
0
    size_t   src_stride, dst_stride; /* Strides through source & destination datatypes */
1511
0
    size_t   i;                      /* Local index variable */
1512
1513
0
    FUNC_ENTER_PACKAGE_NOERR
1514
1515
    /* Check args */
1516
0
    assert(nelmts > 0);
1517
0
    assert(type_info);
1518
1519
    /* Initialize values for loop */
1520
0
    src_stride = type_info->src_type_size;
1521
0
    dst_stride = type_info->dst_type_size;
1522
1523
    /* Loop until all elements are written */
1524
0
    xsbuf = tconv_buf;
1525
0
    xdbuf = tconv_buf;
1526
0
    for (i = 0; i < nelmts; i++) {
1527
0
        memmove(xdbuf, xsbuf, dst_stride);
1528
1529
        /* Update pointers */
1530
0
        xsbuf += src_stride;
1531
0
        xdbuf += dst_stride;
1532
0
    } /* end for */
1533
1534
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1535
0
} /* end H5D__compound_opt_write() */