Coverage Report

Created: 2025-11-11 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Dcontig.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
 * Purpose:
15
 *      Contiguous dataset I/O functions. These routines are similar to
16
 *      the H5D_chunk_* routines and really only an abstract way of dealing
17
 *      with the data sieve buffer from H5F_seq_read/write.
18
 */
19
20
/****************/
21
/* Module Setup */
22
/****************/
23
24
#include "H5Dmodule.h" /* This source code file is part of the H5D module */
25
26
/***********/
27
/* Headers */
28
/***********/
29
#include "H5private.h"   /* Generic Functions            */
30
#include "H5CXprivate.h" /* API Contexts                 */
31
#include "H5Dpkg.h"      /* Dataset functions            */
32
#include "H5Eprivate.h"  /* Error handling               */
33
#include "H5Fprivate.h"  /* Files                        */
34
#include "H5FDprivate.h" /* File drivers                 */
35
#include "H5FLprivate.h" /* Free Lists                   */
36
#include "H5Iprivate.h"  /* IDs                          */
37
#include "H5MFprivate.h" /* File memory management       */
38
#include "H5MMprivate.h" /* Memory management     */
39
#include "H5Oprivate.h"  /* Object headers               */
40
#include "H5PBprivate.h" /* Page Buffer                  */
41
#include "H5VMprivate.h" /* Vector and array functions   */
42
43
/****************/
44
/* Local Macros */
45
/****************/
46
47
/******************/
48
/* Local Typedefs */
49
/******************/
50
51
/* Callback info for sieve buffer readvv operation */
52
typedef struct H5D_contig_readvv_sieve_ud_t {
53
    H5F_shared_t               *f_sh;         /* Shared file for dataset */
54
    H5D_rdcdc_t                *dset_contig;  /* Cached information about contiguous data */
55
    const H5D_contig_storage_t *store_contig; /* Contiguous storage info for this I/O operation */
56
    unsigned char              *rbuf;         /* Pointer to buffer to fill */
57
} H5D_contig_readvv_sieve_ud_t;
58
59
/* Callback info for [plain] readvv operation */
60
typedef struct H5D_contig_readvv_ud_t {
61
    H5F_shared_t  *f_sh;      /* Shared file for dataset */
62
    haddr_t        dset_addr; /* Address of dataset */
63
    unsigned char *rbuf;      /* Pointer to buffer to fill */
64
} H5D_contig_readvv_ud_t;
65
66
/* Callback info for sieve buffer writevv operation */
67
typedef struct H5D_contig_writevv_sieve_ud_t {
68
    H5F_shared_t               *f_sh;         /* Shared file for dataset */
69
    H5D_rdcdc_t                *dset_contig;  /* Cached information about contiguous data */
70
    const H5D_contig_storage_t *store_contig; /* Contiguous storage info for this I/O operation */
71
    const unsigned char        *wbuf;         /* Pointer to buffer to write */
72
} H5D_contig_writevv_sieve_ud_t;
73
74
/* Callback info for [plain] writevv operation */
75
typedef struct H5D_contig_writevv_ud_t {
76
    H5F_shared_t        *f_sh;      /* Shared file for dataset */
77
    haddr_t              dset_addr; /* Address of dataset */
78
    const unsigned char *wbuf;      /* Pointer to buffer to write */
79
} H5D_contig_writevv_ud_t;
80
81
/********************/
82
/* Local Prototypes */
83
/********************/
84
85
/* Layout operation callbacks */
86
static herr_t  H5D__contig_construct(H5F_t *f, H5D_t *dset);
87
static herr_t  H5D__contig_init(H5F_t *f, H5D_t *dset, hid_t dapl_id, bool open_op);
88
static herr_t  H5D__contig_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo);
89
static herr_t  H5D__contig_mdio_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo);
90
static ssize_t H5D__contig_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dinfo,
91
                                  size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[],
92
                                  hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq,
93
                                  size_t mem_len_arr[], hsize_t mem_offset_arr[]);
94
static ssize_t H5D__contig_writevv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dinfo,
95
                                   size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[],
96
                                   hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq,
97
                                   size_t mem_len_arr[], hsize_t mem_offset_arr[]);
98
static herr_t  H5D__contig_flush(H5D_t *dset);
99
static herr_t  H5D__contig_io_term(H5D_io_info_t *io_info, H5D_dset_io_info_t *di);
100
101
/* Helper routines */
102
static herr_t H5D__contig_write_one(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hsize_t offset,
103
                                    size_t size);
104
static herr_t H5D__contig_may_use_select_io(H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info,
105
                                            H5D_io_op_type_t op_type);
106
107
/*********************/
108
/* Package Variables */
109
/*********************/
110
111
/* Contiguous storage layout I/O ops */
112
const H5D_layout_ops_t H5D_LOPS_CONTIG[1] = {{
113
    H5D__contig_construct,      /* construct */
114
    H5D__contig_init,           /* init */
115
    H5D__contig_is_space_alloc, /* is_space_alloc */
116
    H5D__contig_is_data_cached, /* is_data_cached */
117
    H5D__contig_io_init,        /* io_init */
118
    H5D__contig_mdio_init,      /* mdio_init */
119
    H5D__contig_read,           /* ser_read */
120
    H5D__contig_write,          /* ser_write */
121
    H5D__contig_readvv,         /* readvv */
122
    H5D__contig_writevv,        /* writevv */
123
    H5D__contig_flush,          /* flush */
124
    H5D__contig_io_term,        /* io_term */
125
    NULL                        /* dest */
126
}};
127
128
/*******************/
129
/* Local Variables */
130
/*******************/
131
132
/* Declare a PQ free list to manage the sieve buffer information */
133
H5FL_BLK_DEFINE(sieve_buf);
134
135
/* Declare extern the free list to manage blocks of type conversion data */
136
H5FL_BLK_EXTERN(type_conv);
137
138
/* Declare extern the free list to manage the H5D_piece_info_t struct */
139
H5FL_EXTERN(H5D_piece_info_t);
140
141
/*-------------------------------------------------------------------------
142
 * Function:  H5D__contig_alloc
143
 *
144
 * Purpose: Allocate file space for a contiguously stored dataset
145
 *
146
 * Return:  Non-negative on success/Negative on failure
147
 *
148
 *-------------------------------------------------------------------------
149
 */
150
herr_t
151
H5D__contig_alloc(H5F_t *f, H5O_storage_contig_t *storage /*out */)
152
0
{
153
0
    herr_t ret_value = SUCCEED; /* Return value */
154
155
0
    FUNC_ENTER_PACKAGE
156
157
    /* check args */
158
0
    assert(f);
159
0
    assert(storage);
160
161
    /* Allocate space for the contiguous data */
162
0
    if (HADDR_UNDEF == (storage->addr = H5MF_alloc(f, H5FD_MEM_DRAW, storage->size)))
163
0
        HGOTO_ERROR(H5E_IO, H5E_NOSPACE, FAIL, "unable to reserve file space");
164
165
0
done:
166
0
    FUNC_LEAVE_NOAPI(ret_value)
167
0
} /* end H5D__contig_alloc */
168
169
/*-------------------------------------------------------------------------
170
 * Function:  H5D__contig_fill
171
 *
172
 * Purpose: Write fill values to a contiguously stored dataset.
173
 *
174
 * Return:  Non-negative on success/Negative on failure
175
 *
176
 *-------------------------------------------------------------------------
177
 */
178
herr_t
179
H5D__contig_fill(H5D_t *dset)
180
0
{
181
0
    H5D_io_info_t      ioinfo;       /* Dataset I/O info */
182
0
    H5D_dset_io_info_t dset_info;    /* Dset info */
183
0
    H5D_storage_t      store;        /* Union of storage info for dataset */
184
0
    hssize_t           snpoints;     /* Number of points in space (for error checking) */
185
0
    size_t             npoints;      /* Number of points in space */
186
0
    hsize_t            offset;       /* Offset of dataset */
187
0
    size_t             max_temp_buf; /* Maximum size of temporary buffer */
188
#ifdef H5_HAVE_PARALLEL
189
    MPI_Comm mpi_comm = MPI_COMM_NULL; /* MPI communicator for file */
190
    int      mpi_rank = (-1);          /* This process's rank  */
191
    int      mpi_code;                 /* MPI return code */
192
    bool     blocks_written = false;   /* Flag to indicate that chunk was actually written */
193
    bool     using_mpi =
194
        false; /* Flag to indicate that the file is being accessed with an MPI-capable file driver */
195
#endif         /* H5_HAVE_PARALLEL */
196
0
    H5D_fill_buf_info_t fb_info;                /* Dataset's fill buffer info */
197
0
    bool                fb_info_init = false;   /* Whether the fill value buffer has been initialized */
198
0
    herr_t              ret_value    = SUCCEED; /* Return value */
199
200
0
    FUNC_ENTER_PACKAGE
201
202
    /* Check args */
203
0
    assert(dset && H5D_CONTIGUOUS == dset->shared->layout.type);
204
0
    assert(H5_addr_defined(dset->shared->layout.storage.u.contig.addr));
205
0
    assert(dset->shared->layout.storage.u.contig.size > 0);
206
0
    assert(dset->shared->space);
207
0
    assert(dset->shared->type);
208
209
#ifdef H5_HAVE_PARALLEL
210
    /* Retrieve MPI parameters */
211
    if (H5F_HAS_FEATURE(dset->oloc.file, H5FD_FEAT_HAS_MPI)) {
212
        /* Get the MPI communicator */
213
        if (MPI_COMM_NULL == (mpi_comm = H5F_mpi_get_comm(dset->oloc.file)))
214
            HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI communicator");
215
216
        /* Get the MPI rank */
217
        if ((mpi_rank = H5F_mpi_get_rank(dset->oloc.file)) < 0)
218
            HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI rank");
219
220
        /* Set the MPI-capable file driver flag */
221
        using_mpi = true;
222
    }  /* end if */
223
#endif /* H5_HAVE_PARALLEL */
224
225
    /* Initialize storage info for this dataset */
226
0
    store.contig.dset_addr = dset->shared->layout.storage.u.contig.addr;
227
0
    store.contig.dset_size = dset->shared->layout.storage.u.contig.size;
228
229
    /* Get the number of elements in the dataset's dataspace */
230
0
    if ((snpoints = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0)
231
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "dataset has negative number of elements");
232
0
    H5_CHECKED_ASSIGN(npoints, size_t, snpoints, hssize_t);
233
234
    /* Get the maximum size of temporary buffers */
235
0
    if (H5CX_get_max_temp_buf(&max_temp_buf) < 0)
236
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve max. temp. buf size");
237
238
    /* Initialize the fill value buffer */
239
0
    if (H5D__fill_init(&fb_info, NULL, NULL, NULL, NULL, NULL, &dset->shared->dcpl_cache.fill,
240
0
                       dset->shared->type, npoints, max_temp_buf) < 0)
241
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info");
242
0
    fb_info_init = true;
243
244
    /* Start at the beginning of the dataset */
245
0
    offset = 0;
246
247
    /* Simple setup for dataset I/O info struct */
248
0
    ioinfo.op_type = H5D_IO_OP_WRITE;
249
250
0
    dset_info.dset      = (H5D_t *)dset;
251
0
    dset_info.store     = &store;
252
0
    dset_info.buf.cvp   = fb_info.fill_buf;
253
0
    dset_info.mem_space = NULL;
254
0
    ioinfo.dsets_info   = &dset_info;
255
0
    ioinfo.f_sh         = H5F_SHARED(dset->oloc.file);
256
257
    /*
258
     * Fill the entire current extent with the fill value.  We can do
259
     * this quite efficiently by making sure we copy the fill value
260
     * in relatively large pieces.
261
     */
262
263
    /* Loop through writing the fill value to the dataset */
264
0
    while (npoints > 0) {
265
0
        size_t curr_points; /* Number of elements to write on this iteration of the loop */
266
0
        size_t size;        /* Size of buffer to write */
267
268
        /* Compute # of elements and buffer size to write for this iteration */
269
0
        curr_points = MIN(fb_info.elmts_per_buf, npoints);
270
0
        size        = curr_points * fb_info.file_elmt_size;
271
272
        /* Check for VL datatype & non-default fill value */
273
0
        if (fb_info.has_vlen_fill_type)
274
            /* Re-fill the buffer to use for this I/O operation */
275
0
            if (H5D__fill_refill_vl(&fb_info, curr_points) < 0)
276
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer");
277
278
#ifdef H5_HAVE_PARALLEL
279
        /* Check if this file is accessed with an MPI-capable file driver */
280
        if (using_mpi) {
281
            /* Write the chunks out from only one process */
282
            /* !! Use the internal "independent" DXPL!! -QAK */
283
            if (H5_PAR_META_WRITE == mpi_rank) {
284
                if (H5D__contig_write_one(&ioinfo, &dset_info, offset, size) < 0) {
285
                    /* If writing fails, push an error and stop writing, but
286
                     * still participate in following MPI_Barrier.
287
                     */
288
                    blocks_written = true;
289
                    HDONE_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to write fill value to dataset");
290
                    break;
291
                }
292
            }
293
294
            /* Indicate that blocks are being written */
295
            blocks_written = true;
296
        } /* end if */
297
        else {
298
#endif /* H5_HAVE_PARALLEL */
299
0
            H5_CHECK_OVERFLOW(size, size_t, hsize_t);
300
0
            if (H5D__contig_write_one(&ioinfo, &dset_info, offset, size) < 0)
301
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to write fill value to dataset");
302
#ifdef H5_HAVE_PARALLEL
303
        } /* end else */
304
#endif    /* H5_HAVE_PARALLEL */
305
306
0
        npoints -= curr_points;
307
0
        offset += size;
308
0
    } /* end while */
309
310
#ifdef H5_HAVE_PARALLEL
311
    /* Only need to block at the barrier if we actually wrote fill values */
312
    /* And if we are using an MPI-capable file driver */
313
    if (using_mpi && blocks_written) {
314
        /* Wait at barrier to avoid race conditions where some processes are
315
         * still writing out fill values and other processes race ahead to data
316
         * in, getting bogus data.
317
         */
318
        if (MPI_SUCCESS != (mpi_code = MPI_Barrier(mpi_comm)))
319
            HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code)
320
    }  /* end if */
321
#endif /* H5_HAVE_PARALLEL */
322
323
0
done:
324
    /* Release the fill buffer info, if it's been initialized */
325
0
    if (fb_info_init && H5D__fill_term(&fb_info) < 0)
326
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info");
327
328
0
    FUNC_LEAVE_NOAPI(ret_value)
329
0
} /* end H5D__contig_fill() */
330
331
/*-------------------------------------------------------------------------
332
 * Function:  H5D__contig_delete
333
 *
334
 * Purpose: Delete the file space for a contiguously stored dataset
335
 *
336
 * Return:  Non-negative on success/Negative on failure
337
 *
338
 *-------------------------------------------------------------------------
339
 */
340
herr_t
341
H5D__contig_delete(H5F_t *f, const H5O_storage_t *storage)
342
0
{
343
0
    herr_t ret_value = SUCCEED; /* Return value */
344
345
0
    FUNC_ENTER_PACKAGE
346
347
    /* check args */
348
0
    assert(f);
349
0
    assert(storage);
350
351
    /* Free the file space for the chunk */
352
0
    if (H5MF_xfree(f, H5FD_MEM_DRAW, storage->u.contig.addr, storage->u.contig.size) < 0)
353
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to free contiguous storage space");
354
355
0
done:
356
0
    FUNC_LEAVE_NOAPI(ret_value)
357
0
} /* end H5D__contig_delete */
358
359
/*-------------------------------------------------------------------------
360
 * Function:  H5D__contig_check
361
 *
362
 * Purpose: Sanity check the contiguous info for a dataset.
363
 *
364
 * Return:  Non-negative on success/Negative on failure
365
 *
366
 *-------------------------------------------------------------------------
367
 */
368
herr_t
369
H5D__contig_check(const H5F_t *f, const H5O_layout_t *layout, const H5S_extent_t *extent, const H5T_t *dt)
370
18
{
371
18
    hsize_t nelmts;              /* Number of elements in dataspace */
372
18
    size_t  dt_size;             /* Size of datatype */
373
18
    hsize_t data_size;           /* Raw data size */
374
18
    herr_t  ret_value = SUCCEED; /* Return value */
375
376
18
    FUNC_ENTER_PACKAGE
377
378
    /* Sanity check */
379
18
    assert(f);
380
18
    assert(layout);
381
18
    assert(extent);
382
18
    assert(dt);
383
384
    /* Retrieve the number of elements in the dataspace */
385
18
    nelmts = H5S_extent_nelem(extent);
386
387
    /* Get the datatype's size */
388
18
    if (0 == (dt_size = H5T_GET_SIZE(dt)))
389
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve size of datatype");
390
391
    /* Compute the size of the dataset's contiguous storage */
392
18
    data_size = nelmts * dt_size;
393
394
    /* Check for overflow during multiplication */
395
18
    if (nelmts != (data_size / dt_size))
396
0
        HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "size of dataset's storage overflowed");
397
398
    /* Check for invalid (corrupted in the file, probably) dimensions */
399
18
    if (H5_addr_defined(layout->storage.u.contig.addr)) {
400
15
        haddr_t rel_eoa; /* Relative end of file address  */
401
402
15
        if (HADDR_UNDEF == (rel_eoa = H5F_get_eoa(f, H5FD_MEM_DRAW)))
403
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size");
404
405
        /* Check for invalid dataset size (from bad dimensions) putting the
406
         * dataset elements off the end of the file
407
         */
408
15
        if (H5_addr_le((layout->storage.u.contig.addr + data_size), layout->storage.u.contig.addr))
409
1
            HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "invalid dataset size, likely file corruption");
410
14
        if (H5_addr_gt((layout->storage.u.contig.addr + data_size), rel_eoa))
411
8
            HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "invalid dataset size, likely file corruption");
412
14
    }
413
414
18
done:
415
18
    FUNC_LEAVE_NOAPI(ret_value)
416
18
} /* end H5D__contig_check() */
417
418
/*-------------------------------------------------------------------------
419
 * Function:    H5D__contig_construct
420
 *
421
 * Purpose:     Constructs new contiguous layout information for dataset
422
 *              and upgrades layout version if appropriate
423
 *
424
 * Return:      Non-negative on success/Negative on failure
425
 *
426
 *-------------------------------------------------------------------------
427
 */
428
static herr_t
429
H5D__contig_construct(H5F_t *f, H5D_t *dset)
430
0
{
431
0
    hssize_t snelmts;             /* Temporary holder for number of elements in dataspace */
432
0
    hsize_t  nelmts;              /* Number of elements in dataspace */
433
0
    size_t   dt_size;             /* Size of datatype */
434
0
    hsize_t  tmp_size;            /* Temporary holder for raw data size */
435
0
    size_t   tmp_sieve_buf_size;  /* Temporary holder for sieve buffer size */
436
0
    unsigned version;             /* Message version */
437
0
    unsigned u;                   /* Local index variable */
438
0
    herr_t   ret_value = SUCCEED; /* Return value */
439
440
0
    FUNC_ENTER_PACKAGE
441
442
    /* Sanity checks */
443
0
    assert(f);
444
0
    assert(dset);
445
0
    assert(dset->shared);
446
447
    /*
448
     * The maximum size of the dataset cannot exceed the storage size.
449
     * Also, only the slowest varying dimension of a simple dataspace
450
     * can be extendible (currently only for external data storage).
451
     */
452
453
    /* Check for invalid dataset dimensions */
454
0
    for (u = 0; u < dset->shared->ndims; u++)
455
0
        if (dset->shared->max_dims[u] > dset->shared->curr_dims[u])
456
0
            HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL,
457
0
                        "extendible contiguous non-external dataset not allowed");
458
459
    /* Retrieve the number of elements in the dataspace */
460
0
    if ((snelmts = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0)
461
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve number of elements in dataspace");
462
0
    nelmts = (hsize_t)snelmts;
463
464
    /* Get the datatype's size */
465
0
    if (0 == (dt_size = H5T_GET_SIZE(dset->shared->type)))
466
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve size of datatype");
467
468
    /* Compute the size of the dataset's contiguous storage */
469
0
    tmp_size = nelmts * dt_size;
470
471
    /* Check for overflow during multiplication */
472
0
    if (nelmts != (tmp_size / dt_size))
473
0
        HGOTO_ERROR(H5E_DATASET, H5E_OVERFLOW, FAIL, "size of dataset's storage overflowed");
474
475
    /* Assign the dataset's contiguous storage size */
476
0
    dset->shared->layout.storage.u.contig.size = tmp_size;
477
478
    /* Get the sieve buffer size for the file */
479
0
    tmp_sieve_buf_size = H5F_SIEVE_BUF_SIZE(f);
480
481
    /* Adjust the sieve buffer size to the smaller one between the dataset size and the buffer size
482
     * from the file access property. (SLU - 2012/3/30) */
483
0
    if (tmp_size < tmp_sieve_buf_size)
484
0
        dset->shared->cache.contig.sieve_buf_size = tmp_size;
485
0
    else
486
0
        dset->shared->cache.contig.sieve_buf_size = tmp_sieve_buf_size;
487
488
    /* If the layout is below version 3, upgrade to version 3 if allowed. Do not upgrade past version 3 since
489
     * there is no benefit. */
490
0
    if (dset->shared->layout.version < H5O_LAYOUT_VERSION_3) {
491
0
        version = MAX(dset->shared->layout.version,
492
0
                      MIN(H5O_layout_ver_bounds[H5F_LOW_BOUND(f)], H5O_LAYOUT_VERSION_3));
493
494
        /* Version bounds check */
495
0
        if (version > H5O_layout_ver_bounds[H5F_HIGH_BOUND(f)])
496
0
            HGOTO_ERROR(H5E_DATASET, H5E_BADRANGE, FAIL, "layout version out of bounds");
497
498
0
        dset->shared->layout.version = version;
499
0
    }
500
501
0
done:
502
0
    FUNC_LEAVE_NOAPI(ret_value)
503
0
} /* end H5D__contig_construct() */
504
505
/*-------------------------------------------------------------------------
506
 * Function:  H5D__contig_init
507
 *
508
 * Purpose: Initialize the contiguous info for a dataset.  This is
509
 *    called when the dataset is initialized.
510
 *
511
 * Return:  Non-negative on success/Negative on failure
512
 *
513
 *-------------------------------------------------------------------------
514
 */
515
static herr_t
516
H5D__contig_init(H5F_t *f, H5D_t *dset, hid_t H5_ATTR_UNUSED dapl_id, bool H5_ATTR_UNUSED open_op)
517
18
{
518
18
    size_t tmp_sieve_buf_size;  /* Temporary holder for sieve buffer size */
519
18
    herr_t ret_value = SUCCEED; /* Return value */
520
521
18
    FUNC_ENTER_PACKAGE
522
523
    /* Sanity check */
524
18
    assert(f);
525
18
    assert(dset);
526
527
    /* Sanity check the dataset's info */
528
18
    if (H5D__contig_check(f, &dset->shared->layout, H5S_GET_EXTENT(dset->shared->space), dset->shared->type) <
529
18
        0)
530
9
        HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "invalid dataset info");
531
532
    /* Compute the size of the contiguous storage for versions of the
533
     * layout message less than version 3 because versions 1 & 2 would
534
     * truncate the dimension sizes to 32-bits of information. - QAK 5/26/04
535
     */
536
9
    if (dset->shared->layout.version < 3) {
537
7
        hssize_t snelmts; /* Temporary holder for number of elements in dataspace */
538
7
        hsize_t  nelmts;  /* Number of elements in dataspace */
539
7
        size_t   dt_size; /* Size of datatype */
540
541
        /* Retrieve the number of elements in the dataspace */
542
7
        if ((snelmts = H5S_GET_EXTENT_NPOINTS(dset->shared->space)) < 0)
543
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve number of elements in dataspace");
544
7
        nelmts = (hsize_t)snelmts;
545
546
        /* Get the datatype's size */
547
7
        if (0 == (dt_size = H5T_GET_SIZE(dset->shared->type)))
548
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to retrieve size of datatype");
549
550
        /* Compute the size of the dataset's contiguous storage */
551
7
        dset->shared->layout.storage.u.contig.size = nelmts * dt_size;
552
7
    }
553
554
    /* Get the sieve buffer size for the file */
555
9
    tmp_sieve_buf_size = H5F_SIEVE_BUF_SIZE(dset->oloc.file);
556
557
    /* Adjust the sieve buffer size to the smaller one between the dataset size and the buffer size
558
     * from the file access property.  (SLU - 2012/3/30) */
559
9
    if (dset->shared->layout.storage.u.contig.size < tmp_sieve_buf_size)
560
6
        dset->shared->cache.contig.sieve_buf_size = dset->shared->layout.storage.u.contig.size;
561
3
    else
562
3
        dset->shared->cache.contig.sieve_buf_size = tmp_sieve_buf_size;
563
564
18
done:
565
18
    FUNC_LEAVE_NOAPI(ret_value)
566
18
} /* end H5D__contig_init() */
567
568
/*-------------------------------------------------------------------------
569
 * Function:  H5D__contig_is_space_alloc
570
 *
571
 * Purpose: Query if space is allocated for layout
572
 *
573
 * Return:  Non-negative on success/Negative on failure
574
 *
575
 *-------------------------------------------------------------------------
576
 */
577
bool
578
H5D__contig_is_space_alloc(const H5O_storage_t *storage)
579
5
{
580
5
    bool ret_value = false; /* Return value */
581
582
5
    FUNC_ENTER_PACKAGE_NOERR
583
584
    /* Sanity checks */
585
5
    assert(storage);
586
587
    /* Set return value */
588
5
    ret_value = (bool)H5_addr_defined(storage->u.contig.addr);
589
590
5
    FUNC_LEAVE_NOAPI(ret_value)
591
5
} /* end H5D__contig_is_space_alloc() */
592
593
/*-------------------------------------------------------------------------
594
 * Function:    H5D__contig_is_data_cached
595
 *
596
 * Purpose:     Query if raw data is cached for dataset
597
 *
598
 * Return:      Non-negative on success/Negative on failure
599
 *
600
 *-------------------------------------------------------------------------
601
 */
602
bool
603
H5D__contig_is_data_cached(const H5D_shared_t *shared_dset)
604
0
{
605
0
    FUNC_ENTER_PACKAGE_NOERR
606
607
    /* Sanity checks */
608
0
    assert(shared_dset);
609
610
0
    FUNC_LEAVE_NOAPI(shared_dset->cache.contig.sieve_size > 0)
611
0
} /* end H5D__contig_is_data_cached() */
612
613
/*-------------------------------------------------------------------------
614
 * Function:  H5D__contig_io_init
615
 *
616
 * Purpose: Performs initialization before any sort of I/O on the raw data
617
 *
618
 * Return:  Non-negative on success/Negative on failure
619
 *
620
 *-------------------------------------------------------------------------
621
 */
622
static herr_t
623
H5D__contig_io_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo)
624
0
{
625
0
    H5D_t *dataset = dinfo->dset; /* Local pointer to dataset info */
626
627
0
    hssize_t old_offset[H5O_LAYOUT_NDIMS];  /* Old selection offset */
628
0
    htri_t   file_space_normalized = false; /* File dataspace was normalized */
629
630
0
    int sf_ndims; /* The number of dimensions of the file dataspace (signed) */
631
632
0
    herr_t ret_value = SUCCEED; /* Return value */
633
634
0
    FUNC_ENTER_PACKAGE
635
636
0
    dinfo->store->contig.dset_addr = dataset->shared->layout.storage.u.contig.addr;
637
0
    dinfo->store->contig.dset_size = dataset->shared->layout.storage.u.contig.size;
638
639
    /* Initialize piece info */
640
0
    dinfo->layout_io_info.contig_piece_info = NULL;
641
642
    /* Get layout for dataset */
643
0
    dinfo->layout = &(dataset->shared->layout);
644
645
    /* Get dim number and dimensionality for each dataspace */
646
0
    if ((sf_ndims = H5S_GET_EXTENT_NDIMS(dinfo->file_space)) < 0)
647
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number");
648
649
    /* Normalize hyperslab selections by adjusting them by the offset */
650
    /* (It might be worthwhile to normalize both the file and memory dataspaces
651
     * before any (contiguous, chunked, etc) file I/O operation, in order to
652
     * speed up hyperslab calculations by removing the extra checks and/or
653
     * additions involving the offset and the hyperslab selection -QAK)
654
     */
655
0
    if ((file_space_normalized = H5S_hyper_normalize_offset(dinfo->file_space, old_offset)) < 0)
656
0
        HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset");
657
658
    /* if selected elements exist */
659
0
    if (dinfo->nelmts) {
660
0
        int               u;
661
0
        H5D_piece_info_t *new_piece_info; /* piece information to insert into skip list */
662
663
        /* Get copy of dset file_space, so it can be changed temporarily
664
         * purpose
665
         * This tmp_fspace allows multiple write before close dset */
666
0
        H5S_t *tmp_fspace; /* Temporary file dataspace */
667
668
        /* Create "temporary" chunk for selection operations (copy file space) */
669
0
        if (NULL == (tmp_fspace = H5S_copy(dinfo->file_space, true, false)))
670
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space");
671
672
        /* Add temporary chunk to the list of pieces */
673
        /* collect piece_info into Skip List */
674
        /* Allocate the file & memory chunk information */
675
0
        if (NULL == (new_piece_info = H5FL_MALLOC(H5D_piece_info_t))) {
676
0
            (void)H5S_close(tmp_fspace);
677
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info");
678
0
        } /* end if */
679
680
        /* Set the piece index */
681
0
        new_piece_info->index = 0;
682
683
        /* Set the file chunk dataspace */
684
0
        new_piece_info->fspace        = tmp_fspace;
685
0
        new_piece_info->fspace_shared = false;
686
687
        /* Set the memory chunk dataspace */
688
        /* same as one chunk, just use dset mem space */
689
0
        new_piece_info->mspace = dinfo->mem_space;
690
691
        /* set true for sharing mem space with dset, which means
692
         * fspace gets free by application H5Sclose(), and
693
         * doesn't require providing layout_ops.io_term() for H5D_LOPS_CONTIG.
694
         */
695
0
        new_piece_info->mspace_shared = true;
696
697
        /* Set the number of points */
698
0
        new_piece_info->piece_points = dinfo->nelmts;
699
700
        /* Copy the piece's coordinates */
701
0
        for (u = 0; u < sf_ndims; u++)
702
0
            new_piece_info->scaled[u] = 0;
703
0
        new_piece_info->scaled[sf_ndims] = 0;
704
705
        /* make connection to related dset info from this piece_info */
706
0
        new_piece_info->dset_info = dinfo;
707
708
        /* get dset file address for piece */
709
0
        new_piece_info->faddr = dinfo->dset->shared->layout.storage.u.contig.addr;
710
711
        /* Initialize in-place type conversion info. Start with it disabled. */
712
0
        new_piece_info->in_place_tconv = false;
713
0
        new_piece_info->buf_off        = 0;
714
715
0
        new_piece_info->filtered_dset = dinfo->dset->shared->dcpl_cache.pline.nused > 0;
716
717
        /* Calculate type conversion buffer size and check for in-place conversion if necessary.  Currently
718
         * only implemented for selection I/O. */
719
0
        if (io_info->use_select_io != H5D_SELECTION_IO_MODE_OFF &&
720
0
            !(dinfo->type_info.is_xform_noop && dinfo->type_info.is_conv_noop))
721
0
            H5D_INIT_PIECE_TCONV(io_info, dinfo, new_piece_info)
722
723
        /* Save piece to dataset info struct so it is freed at the end of the
724
         * operation */
725
0
        dinfo->layout_io_info.contig_piece_info = new_piece_info;
726
727
        /* Add piece to piece_count */
728
0
        io_info->piece_count++;
729
0
    } /* end if */
730
731
    /* Check if we're performing selection I/O if it hasn't been disabled
732
     * already */
733
0
    if (io_info->use_select_io != H5D_SELECTION_IO_MODE_OFF)
734
0
        if (H5D__contig_may_use_select_io(io_info, dinfo, io_info->op_type) < 0)
735
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if selection I/O is possible");
736
737
0
done:
738
0
    if (ret_value < 0) {
739
0
        if (H5D__contig_io_term(io_info, dinfo) < 0)
740
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataset I/O info");
741
0
    } /* end if */
742
743
0
    if (file_space_normalized) {
744
        /* (Casting away const OK -QAK) */
745
0
        if (H5S_hyper_denormalize_offset(dinfo->file_space, old_offset) < 0)
746
0
            HDONE_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset");
747
0
    } /* end if */
748
749
0
    FUNC_LEAVE_NOAPI(ret_value)
750
0
} /* end H5D__contig_io_init() */
751
752
/*-------------------------------------------------------------------------
753
 * Function:   H5D__contig_mdio_init
754
 *
755
 * Purpose:    Performs second phase of initialization for multi-dataset
756
 *             I/O.  Currently just adds data block to sel_pieces.
757
 *
758
 * Return:     Non-negative on success/Negative on failure
759
 *
760
 *-------------------------------------------------------------------------
761
 */
762
static herr_t
763
H5D__contig_mdio_init(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo)
764
0
{
765
0
    FUNC_ENTER_PACKAGE_NOERR
766
767
    /* Add piece if it exists */
768
0
    if (dinfo->layout_io_info.contig_piece_info) {
769
0
        assert(io_info->sel_pieces);
770
0
        assert(io_info->pieces_added < io_info->piece_count);
771
772
        /* Add contiguous data block to sel_pieces */
773
0
        io_info->sel_pieces[io_info->pieces_added] = dinfo->layout_io_info.contig_piece_info;
774
775
        /* Update pieces_added */
776
0
        io_info->pieces_added++;
777
0
    }
778
779
0
    FUNC_LEAVE_NOAPI(SUCCEED)
780
0
} /* end H5D__contig_mdio_init() */
781
782
/*-------------------------------------------------------------------------
783
 * Function:    H5D__contig_may_use_select_io
784
 *
785
 * Purpose:    A small internal function to if it may be possible to use
786
 *             selection I/O.
787
 *
788
 * Return:    true/false/FAIL
789
 *
790
 *-------------------------------------------------------------------------
791
 */
792
static herr_t
793
H5D__contig_may_use_select_io(H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info,
794
                              H5D_io_op_type_t op_type)
795
0
{
796
0
    const H5D_t *dataset   = NULL;    /* Local pointer to dataset info */
797
0
    herr_t       ret_value = SUCCEED; /* Return value */
798
799
0
    FUNC_ENTER_PACKAGE
800
801
    /* Sanity check */
802
0
    assert(io_info);
803
0
    assert(dset_info);
804
0
    assert(dset_info->dset);
805
0
    assert(op_type == H5D_IO_OP_READ || op_type == H5D_IO_OP_WRITE);
806
807
0
    dataset = dset_info->dset;
808
809
    /* None of the reasons this function might disable selection I/O are relevant to parallel, so no need to
810
     * update no_selection_io_cause since we're only keeping track of the reason for no selection I/O in
811
     * parallel (for now) */
812
813
    /* Don't use selection I/O if it's globally disabled, if it's not a contiguous dataset, or if the sieve
814
     * buffer exists (write) or is dirty (read) */
815
0
    if (dset_info->layout_ops.readvv != H5D__contig_readvv) {
816
0
        io_info->use_select_io = H5D_SELECTION_IO_MODE_OFF;
817
0
        io_info->no_selection_io_cause |= H5D_SEL_IO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET;
818
0
    }
819
0
    else if ((op_type == H5D_IO_OP_READ && dataset->shared->cache.contig.sieve_dirty) ||
820
0
             (op_type == H5D_IO_OP_WRITE && dataset->shared->cache.contig.sieve_buf)) {
821
0
        io_info->use_select_io = H5D_SELECTION_IO_MODE_OFF;
822
0
        io_info->no_selection_io_cause |= H5D_SEL_IO_CONTIGUOUS_SIEVE_BUFFER;
823
0
    }
824
0
    else {
825
0
        bool page_buf_enabled;
826
827
0
        assert(dset_info->layout_ops.writevv == H5D__contig_writevv);
828
829
        /* Check if the page buffer is enabled */
830
0
        if (H5PB_enabled(io_info->f_sh, H5FD_MEM_DRAW, &page_buf_enabled) < 0)
831
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't check if page buffer is enabled");
832
0
        if (page_buf_enabled) {
833
0
            io_info->use_select_io = H5D_SELECTION_IO_MODE_OFF;
834
0
            io_info->no_selection_io_cause |= H5D_SEL_IO_PAGE_BUFFER;
835
0
        }
836
0
    } /* end else */
837
838
0
done:
839
0
    FUNC_LEAVE_NOAPI(ret_value)
840
0
} /* end H5D__contig_may_use_select_io() */
841
842
/*-------------------------------------------------------------------------
843
 * Function:  H5D__contig_read
844
 *
845
 * Purpose: Read from a contiguous dataset.
846
 *
847
 * Return:  Non-negative on success/Negative on failure
848
 *
849
 *-------------------------------------------------------------------------
850
 */
851
herr_t
852
H5D__contig_read(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo)
853
0
{
854
0
    herr_t ret_value = SUCCEED; /* Return value */
855
856
0
    FUNC_ENTER_PACKAGE
857
858
    /* Sanity check */
859
0
    assert(io_info);
860
0
    assert(dinfo);
861
0
    assert(dinfo->buf.vp);
862
0
    assert(dinfo->mem_space);
863
0
    assert(dinfo->file_space);
864
865
0
    if (io_info->use_select_io == H5D_SELECTION_IO_MODE_ON) {
866
        /* Only perform I/O if not performing multi dataset I/O or type conversion,
867
         * otherwise the higher level will handle it after all datasets
868
         * have been processed */
869
0
        if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) {
870
0
            size_t dst_type_size = dinfo->type_info.dst_type_size;
871
872
            /* Issue selection I/O call (we can skip the page buffer because we've
873
             * already verified it won't be used, and the metadata accumulator
874
             * because this is raw data) */
875
0
            if (H5F_shared_select_read(H5F_SHARED(dinfo->dset->oloc.file), H5FD_MEM_DRAW,
876
0
                                       dinfo->nelmts > 0 ? 1 : 0, &dinfo->mem_space, &dinfo->file_space,
877
0
                                       &(dinfo->store->contig.dset_addr), &dst_type_size,
878
0
                                       &(dinfo->buf.vp)) < 0)
879
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous selection read failed");
880
0
        }
881
0
        else {
882
0
            if (dinfo->layout_io_info.contig_piece_info) {
883
                /* Add to mdset selection I/O arrays */
884
0
                assert(io_info->mem_spaces);
885
0
                assert(io_info->file_spaces);
886
0
                assert(io_info->addrs);
887
0
                assert(io_info->element_sizes);
888
0
                assert(io_info->rbufs);
889
0
                assert(io_info->pieces_added < io_info->piece_count);
890
891
0
                io_info->mem_spaces[io_info->pieces_added]    = dinfo->mem_space;
892
0
                io_info->file_spaces[io_info->pieces_added]   = dinfo->file_space;
893
0
                io_info->addrs[io_info->pieces_added]         = dinfo->store->contig.dset_addr;
894
0
                io_info->element_sizes[io_info->pieces_added] = dinfo->type_info.src_type_size;
895
0
                io_info->rbufs[io_info->pieces_added]         = dinfo->buf.vp;
896
0
                if (io_info->sel_pieces)
897
0
                    io_info->sel_pieces[io_info->pieces_added] = dinfo->layout_io_info.contig_piece_info;
898
0
                io_info->pieces_added++;
899
0
            }
900
0
        }
901
902
#ifdef H5_HAVE_PARALLEL
903
        /* Report that collective contiguous I/O was used */
904
        io_info->actual_io_mode |= H5D_MPIO_CONTIGUOUS_COLLECTIVE;
905
#endif /* H5_HAVE_PARALLEL */
906
0
    }  /* end if */
907
0
    else
908
        /* Read data through legacy (non-selection I/O) pathway */
909
0
        if ((dinfo->io_ops.single_read)(io_info, dinfo) < 0)
910
0
            HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous read failed");
911
912
0
done:
913
0
    FUNC_LEAVE_NOAPI(ret_value)
914
0
} /* end H5D__contig_read() */
915
916
/*-------------------------------------------------------------------------
917
 * Function:  H5D__contig_write
918
 *
919
 * Purpose: Write to a contiguous dataset.
920
 *
921
 * Return:  Non-negative on success/Negative on failure
922
 *
923
 *-------------------------------------------------------------------------
924
 */
925
herr_t
926
H5D__contig_write(H5D_io_info_t *io_info, H5D_dset_io_info_t *dinfo)
927
0
{
928
0
    herr_t ret_value = SUCCEED; /* Return value */
929
930
0
    FUNC_ENTER_PACKAGE
931
932
    /* Sanity check */
933
0
    assert(io_info);
934
0
    assert(dinfo);
935
0
    assert(dinfo->buf.cvp);
936
0
    assert(dinfo->mem_space);
937
0
    assert(dinfo->file_space);
938
939
0
    if (io_info->use_select_io == H5D_SELECTION_IO_MODE_ON) {
940
        /* Only perform I/O if not performing multi dataset I/O or type conversion,
941
         * otherwise the higher level will handle it after all datasets
942
         * have been processed */
943
0
        if (H5D_LAYOUT_CB_PERFORM_IO(io_info)) {
944
0
            size_t dst_type_size = dinfo->type_info.dst_type_size;
945
946
            /* Issue selection I/O call (we can skip the page buffer because we've
947
             * already verified it won't be used, and the metadata accumulator
948
             * because this is raw data) */
949
0
            if (H5F_shared_select_write(H5F_SHARED(dinfo->dset->oloc.file), H5FD_MEM_DRAW,
950
0
                                        dinfo->nelmts > 0 ? 1 : 0, &dinfo->mem_space, &dinfo->file_space,
951
0
                                        &(dinfo->store->contig.dset_addr), &dst_type_size,
952
0
                                        &(dinfo->buf.cvp)) < 0)
953
0
                HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous selection write failed");
954
0
        }
955
0
        else {
956
0
            if (dinfo->layout_io_info.contig_piece_info) {
957
                /* Add to mdset selection I/O arrays */
958
0
                assert(io_info->mem_spaces);
959
0
                assert(io_info->file_spaces);
960
0
                assert(io_info->addrs);
961
0
                assert(io_info->element_sizes);
962
0
                assert(io_info->wbufs);
963
0
                assert(io_info->pieces_added < io_info->piece_count);
964
965
0
                io_info->mem_spaces[io_info->pieces_added]    = dinfo->mem_space;
966
0
                io_info->file_spaces[io_info->pieces_added]   = dinfo->file_space;
967
0
                io_info->addrs[io_info->pieces_added]         = dinfo->store->contig.dset_addr;
968
0
                io_info->element_sizes[io_info->pieces_added] = dinfo->type_info.dst_type_size;
969
0
                io_info->wbufs[io_info->pieces_added]         = dinfo->buf.cvp;
970
0
                if (io_info->sel_pieces)
971
0
                    io_info->sel_pieces[io_info->pieces_added] = dinfo->layout_io_info.contig_piece_info;
972
0
                io_info->pieces_added++;
973
0
            }
974
0
        }
975
976
#ifdef H5_HAVE_PARALLEL
977
        /* Report that collective contiguous I/O was used */
978
        io_info->actual_io_mode |= H5D_MPIO_CONTIGUOUS_COLLECTIVE;
979
#endif /* H5_HAVE_PARALLEL */
980
0
    }  /* end if */
981
0
    else
982
        /* Write data through legacy (non-selection I/O) pathway */
983
0
        if ((dinfo->io_ops.single_write)(io_info, dinfo) < 0)
984
0
            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous write failed");
985
986
0
done:
987
0
    FUNC_LEAVE_NOAPI(ret_value)
988
0
} /* end H5D__contig_write() */
989
990
/*-------------------------------------------------------------------------
991
 * Function:  H5D__contig_write_one
992
 *
993
 * Purpose: Writes some data from a dataset into a buffer.
994
 *    The data is contiguous.  The address is relative to the base
995
 *    address for the file.
996
 *
997
 * Return:  Non-negative on success/Negative on failure
998
 *
999
 *-------------------------------------------------------------------------
1000
 */
1001
static herr_t
1002
H5D__contig_write_one(H5D_io_info_t *io_info, H5D_dset_io_info_t *dset_info, hsize_t offset, size_t size)
1003
0
{
1004
0
    hsize_t dset_off      = offset;  /* Offset in dataset */
1005
0
    size_t  dset_len      = size;    /* Length in dataset */
1006
0
    size_t  dset_curr_seq = 0;       /* "Current sequence" in dataset */
1007
0
    hsize_t mem_off       = 0;       /* Offset in memory */
1008
0
    size_t  mem_len       = size;    /* Length in memory */
1009
0
    size_t  mem_curr_seq  = 0;       /* "Current sequence" in memory */
1010
0
    herr_t  ret_value     = SUCCEED; /* Return value */
1011
1012
0
    FUNC_ENTER_PACKAGE
1013
1014
0
    assert(io_info);
1015
1016
0
    if (H5D__contig_writevv(io_info, dset_info, (size_t)1, &dset_curr_seq, &dset_len, &dset_off, (size_t)1,
1017
0
                            &mem_curr_seq, &mem_len, &mem_off) < 0)
1018
0
        HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vector write failed");
1019
1020
0
done:
1021
0
    FUNC_LEAVE_NOAPI(ret_value)
1022
0
} /* end H5D__contig_write_one() */
1023
1024
/*-------------------------------------------------------------------------
1025
 * Function:  H5D__contig_readvv_sieve_cb
1026
 *
1027
 * Purpose: Callback operator for H5D__contig_readvv() with sieve buffer.
1028
 *
1029
 * Return:  Non-negative on success/Negative on failure
1030
 *
1031
 *-------------------------------------------------------------------------
1032
 */
1033
static herr_t
1034
H5D__contig_readvv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata)
1035
0
{
1036
0
    H5D_contig_readvv_sieve_ud_t *udata =
1037
0
        (H5D_contig_readvv_sieve_ud_t *)_udata;     /* User data for H5VM_opvv() operator */
1038
0
    H5F_shared_t *f_sh        = udata->f_sh;        /* Shared file for dataset */
1039
0
    H5D_rdcdc_t  *dset_contig = udata->dset_contig; /* Cached information about contiguous data */
1040
0
    const H5D_contig_storage_t *store_contig =
1041
0
        udata->store_contig; /* Contiguous storage info for this I/O operation */
1042
0
    unsigned char *buf;      /* Pointer to buffer to fill */
1043
0
    haddr_t        addr;     /* Actual address to read */
1044
0
    haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */
1045
0
    haddr_t contig_end;                                         /* End locations of block to write */
1046
0
    size_t  sieve_size = (size_t)-1;                            /* Size of sieve buffer */
1047
0
    haddr_t rel_eoa;                                            /* Relative end of file address */
1048
0
    hsize_t max_data;                                           /* Actual maximum size of data to cache */
1049
0
    hsize_t min;                 /* temporary minimum value (avoids some ugly macro nesting) */
1050
0
    herr_t  ret_value = SUCCEED; /* Return value */
1051
1052
0
    FUNC_ENTER_PACKAGE
1053
1054
    /* Stash local copies of these value */
1055
0
    if (dset_contig->sieve_buf != NULL) {
1056
0
        sieve_start = dset_contig->sieve_loc;
1057
0
        sieve_size  = dset_contig->sieve_size;
1058
0
        sieve_end   = sieve_start + sieve_size;
1059
0
    } /* end if */
1060
1061
    /* Compute offset on disk */
1062
0
    addr = store_contig->dset_addr + dst_off;
1063
1064
    /* Compute offset in memory */
1065
0
    buf = udata->rbuf + src_off;
1066
1067
    /* Check if the sieve buffer is allocated yet */
1068
0
    if (NULL == dset_contig->sieve_buf) {
1069
        /* Check if we can actually hold the I/O request in the sieve buffer */
1070
0
        if (len > dset_contig->sieve_buf_size) {
1071
0
            if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, addr, len, buf) < 0)
1072
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed");
1073
0
        } /* end if */
1074
0
        else {
1075
            /* Allocate room for the data sieve buffer */
1076
0
            if (NULL == (dset_contig->sieve_buf = H5FL_BLK_CALLOC(sieve_buf, dset_contig->sieve_buf_size)))
1077
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed");
1078
1079
            /* Determine the new sieve buffer size & location */
1080
0
            dset_contig->sieve_loc = addr;
1081
1082
            /* Make certain we don't read off the end of the file */
1083
0
            if (HADDR_UNDEF == (rel_eoa = H5F_shared_get_eoa(f_sh, H5FD_MEM_DRAW)))
1084
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size");
1085
1086
            /* Set up the buffer parameters */
1087
0
            max_data = store_contig->dset_size - dst_off;
1088
1089
            /* Compute the size of the sieve buffer */
1090
0
            min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size);
1091
0
            H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t);
1092
1093
            /* Read the new sieve buffer */
1094
0
            if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size,
1095
0
                                      dset_contig->sieve_buf) < 0)
1096
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed");
1097
1098
            /* Grab the data out of the buffer (must be first piece of data in buffer ) */
1099
0
            H5MM_memcpy(buf, dset_contig->sieve_buf, len);
1100
1101
            /* Reset sieve buffer dirty flag */
1102
0
            dset_contig->sieve_dirty = false;
1103
0
        } /* end else */
1104
0
    }     /* end if */
1105
0
    else {
1106
        /* Compute end of sequence to retrieve */
1107
0
        contig_end = addr + len - 1;
1108
1109
        /* If entire read is within the sieve buffer, read it from the buffer */
1110
0
        if (addr >= sieve_start && contig_end < sieve_end) {
1111
0
            unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start);
1112
1113
            /* Grab the data out of the buffer */
1114
0
            H5MM_memcpy(buf, base_sieve_buf, len);
1115
0
        } /* end if */
1116
        /* Entire request is not within this data sieve buffer */
1117
0
        else {
1118
            /* Check if we can actually hold the I/O request in the sieve buffer */
1119
0
            if (len > dset_contig->sieve_buf_size) {
1120
                /* Check for any overlap with the current sieve buffer */
1121
0
                if ((sieve_start >= addr && sieve_start < (contig_end + 1)) ||
1122
0
                    ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) {
1123
                    /* Flush the sieve buffer, if it's dirty */
1124
0
                    if (dset_contig->sieve_dirty) {
1125
                        /* Write to file */
1126
0
                        if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, sieve_start, sieve_size,
1127
0
                                                   dset_contig->sieve_buf) < 0)
1128
0
                            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed");
1129
1130
                        /* Reset sieve buffer dirty flag */
1131
0
                        dset_contig->sieve_dirty = false;
1132
0
                    } /* end if */
1133
0
                }     /* end if */
1134
1135
                /* Read directly into the user's buffer */
1136
0
                if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, addr, len, buf) < 0)
1137
0
                    HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed");
1138
0
            } /* end if */
1139
            /* Element size fits within the buffer size */
1140
0
            else {
1141
                /* Flush the sieve buffer if it's dirty */
1142
0
                if (dset_contig->sieve_dirty) {
1143
                    /* Write to file */
1144
0
                    if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, sieve_start, sieve_size,
1145
0
                                               dset_contig->sieve_buf) < 0)
1146
0
                        HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed");
1147
1148
                    /* Reset sieve buffer dirty flag */
1149
0
                    dset_contig->sieve_dirty = false;
1150
0
                } /* end if */
1151
1152
                /* Determine the new sieve buffer size & location */
1153
0
                dset_contig->sieve_loc = addr;
1154
1155
                /* Make certain we don't read off the end of the file */
1156
0
                if (HADDR_UNDEF == (rel_eoa = H5F_shared_get_eoa(f_sh, H5FD_MEM_DRAW)))
1157
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size");
1158
1159
                /* Only need this when resizing sieve buffer */
1160
0
                max_data = store_contig->dset_size - dst_off;
1161
1162
                /* Compute the size of the sieve buffer.
1163
                 * Don't read off the end of the file, don't read past
1164
                 * the end of the data element, and don't read more than
1165
                 * the buffer size.
1166
                 */
1167
0
                min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size);
1168
0
                H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t);
1169
1170
                /* Read the new sieve buffer */
1171
0
                if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, dset_contig->sieve_loc,
1172
0
                                          dset_contig->sieve_size, dset_contig->sieve_buf) < 0)
1173
0
                    HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed");
1174
1175
                /* Grab the data out of the buffer (must be first piece of data in buffer ) */
1176
0
                H5MM_memcpy(buf, dset_contig->sieve_buf, len);
1177
1178
                /* Reset sieve buffer dirty flag */
1179
0
                dset_contig->sieve_dirty = false;
1180
0
            } /* end else */
1181
0
        }     /* end else */
1182
0
    }         /* end else */
1183
1184
0
done:
1185
0
    FUNC_LEAVE_NOAPI(ret_value)
1186
0
} /* end H5D__contig_readvv_sieve_cb() */
1187
1188
/*-------------------------------------------------------------------------
1189
 * Function:  H5D__contig_readvv_cb
1190
 *
1191
 * Purpose: Callback operator for H5D__contig_readvv() without sieve buffer.
1192
 *
1193
 * Return:  Non-negative on success/Negative on failure
1194
 *
1195
 *-------------------------------------------------------------------------
1196
 */
1197
static herr_t
1198
H5D__contig_readvv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata)
1199
0
{
1200
0
    H5D_contig_readvv_ud_t *udata = (H5D_contig_readvv_ud_t *)_udata; /* User data for H5VM_opvv() operator */
1201
0
    herr_t                  ret_value = SUCCEED;                      /* Return value */
1202
1203
0
    FUNC_ENTER_PACKAGE
1204
1205
    /* Write data */
1206
0
    if (H5F_shared_block_read(udata->f_sh, H5FD_MEM_DRAW, (udata->dset_addr + dst_off), len,
1207
0
                              (udata->rbuf + src_off)) < 0)
1208
0
        HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed");
1209
1210
0
done:
1211
0
    FUNC_LEAVE_NOAPI(ret_value)
1212
0
} /* end H5D__contig_readvv_cb() */
1213
1214
/*-------------------------------------------------------------------------
1215
 * Function:  H5D__contig_readvv
1216
 *
1217
 * Purpose: Reads some data vectors from a dataset into a buffer.
1218
 *    The data is contiguous.  The address is the start of the dataset,
1219
 *              relative to the base address for the file and the offsets and
1220
 *              sequence lengths are in bytes.
1221
 *
1222
 * Return:  Non-negative on success/Negative on failure
1223
 *
1224
 * Notes:
1225
 *      Offsets in the sequences must be monotonically increasing
1226
 *
1227
 *-------------------------------------------------------------------------
1228
 */
1229
static ssize_t
1230
H5D__contig_readvv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, size_t dset_max_nseq,
1231
                   size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq,
1232
                   size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[])
1233
0
{
1234
0
    ssize_t ret_value = -1; /* Return value */
1235
1236
0
    FUNC_ENTER_PACKAGE
1237
1238
    /* Check args */
1239
0
    assert(io_info);
1240
0
    assert(dset_info);
1241
0
    assert(dset_curr_seq);
1242
0
    assert(dset_len_arr);
1243
0
    assert(dset_off_arr);
1244
0
    assert(mem_curr_seq);
1245
0
    assert(mem_len_arr);
1246
0
    assert(mem_off_arr);
1247
1248
    /* Check if data sieving is enabled */
1249
0
    if (H5F_SHARED_HAS_FEATURE(io_info->f_sh, H5FD_FEAT_DATA_SIEVE)) {
1250
0
        H5D_contig_readvv_sieve_ud_t udata; /* User data for H5VM_opvv() operator */
1251
1252
        /* Set up user data for H5VM_opvv() */
1253
0
        udata.f_sh         = io_info->f_sh;
1254
0
        udata.dset_contig  = &(dset_info->dset->shared->cache.contig);
1255
0
        udata.store_contig = &(dset_info->store->contig);
1256
0
        udata.rbuf         = (unsigned char *)dset_info->buf.vp;
1257
1258
        /* Call generic sequence operation routine */
1259
0
        if ((ret_value =
1260
0
                 H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq,
1261
0
                           mem_curr_seq, mem_len_arr, mem_off_arr, H5D__contig_readvv_sieve_cb, &udata)) < 0)
1262
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized sieve buffer read");
1263
0
    } /* end if */
1264
0
    else {
1265
0
        H5D_contig_readvv_ud_t udata; /* User data for H5VM_opvv() operator */
1266
1267
        /* Set up user data for H5VM_opvv() */
1268
0
        udata.f_sh      = io_info->f_sh;
1269
0
        udata.dset_addr = dset_info->store->contig.dset_addr;
1270
0
        udata.rbuf      = (unsigned char *)dset_info->buf.vp;
1271
1272
        /* Call generic sequence operation routine */
1273
0
        if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq,
1274
0
                                   mem_curr_seq, mem_len_arr, mem_off_arr, H5D__contig_readvv_cb, &udata)) <
1275
0
            0)
1276
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized read");
1277
0
    } /* end else */
1278
1279
0
done:
1280
0
    FUNC_LEAVE_NOAPI(ret_value)
1281
0
} /* end H5D__contig_readvv() */
1282
1283
/*-------------------------------------------------------------------------
1284
 * Function:  H5D__contig_writevv_sieve_cb
1285
 *
1286
 * Purpose: Callback operator for H5D__contig_writevv() with sieve buffer.
1287
 *
1288
 * Return:  Non-negative on success/Negative on failure
1289
 *
1290
 *-------------------------------------------------------------------------
1291
 */
1292
static herr_t
1293
H5D__contig_writevv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata)
1294
0
{
1295
0
    H5D_contig_writevv_sieve_ud_t *udata =
1296
0
        (H5D_contig_writevv_sieve_ud_t *)_udata;    /* User data for H5VM_opvv() operator */
1297
0
    H5F_shared_t *f_sh        = udata->f_sh;        /* Shared file for dataset */
1298
0
    H5D_rdcdc_t  *dset_contig = udata->dset_contig; /* Cached information about contiguous data */
1299
0
    const H5D_contig_storage_t *store_contig =
1300
0
        udata->store_contig;   /* Contiguous storage info for this I/O operation */
1301
0
    const unsigned char *buf;  /* Pointer to buffer to fill */
1302
0
    haddr_t              addr; /* Actual address to read */
1303
0
    haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */
1304
0
    haddr_t contig_end;                                         /* End locations of block to write */
1305
0
    size_t  sieve_size = (size_t)-1;                            /* size of sieve buffer */
1306
0
    haddr_t rel_eoa;                                            /* Relative end of file address */
1307
0
    hsize_t max_data;                                           /* Actual maximum size of data to cache */
1308
0
    hsize_t min;                 /* temporary minimum value (avoids some ugly macro nesting) */
1309
0
    herr_t  ret_value = SUCCEED; /* Return value */
1310
1311
0
    FUNC_ENTER_PACKAGE
1312
1313
    /* Stash local copies of these values */
1314
0
    if (dset_contig->sieve_buf != NULL) {
1315
0
        sieve_start = dset_contig->sieve_loc;
1316
0
        sieve_size  = dset_contig->sieve_size;
1317
0
        sieve_end   = sieve_start + sieve_size;
1318
0
    } /* end if */
1319
1320
    /* Compute offset on disk */
1321
0
    addr = store_contig->dset_addr + dst_off;
1322
1323
    /* Compute offset in memory */
1324
0
    buf = udata->wbuf + src_off;
1325
1326
    /* No data sieve buffer yet, go allocate one */
1327
0
    if (NULL == dset_contig->sieve_buf) {
1328
        /* Check if we can actually hold the I/O request in the sieve buffer */
1329
0
        if (len > dset_contig->sieve_buf_size) {
1330
0
            if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, addr, len, buf) < 0)
1331
0
                HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed");
1332
0
        } /* end if */
1333
0
        else {
1334
            /* Allocate room for the data sieve buffer */
1335
0
            if (NULL == (dset_contig->sieve_buf = H5FL_BLK_CALLOC(sieve_buf, dset_contig->sieve_buf_size)))
1336
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed");
1337
1338
            /* Clear memory */
1339
0
            if (dset_contig->sieve_size > len)
1340
0
                memset(dset_contig->sieve_buf + len, 0, (dset_contig->sieve_size - len));
1341
1342
            /* Determine the new sieve buffer size & location */
1343
0
            dset_contig->sieve_loc = addr;
1344
1345
            /* Make certain we don't read off the end of the file */
1346
0
            if (HADDR_UNDEF == (rel_eoa = H5F_shared_get_eoa(f_sh, H5FD_MEM_DRAW)))
1347
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size");
1348
1349
            /* Set up the buffer parameters */
1350
0
            max_data = store_contig->dset_size - dst_off;
1351
1352
            /* Compute the size of the sieve buffer */
1353
0
            min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size);
1354
0
            H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t);
1355
1356
            /* Check if there is any point in reading the data from the file */
1357
0
            if (dset_contig->sieve_size > len) {
1358
                /* Read the new sieve buffer */
1359
0
                if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, dset_contig->sieve_loc,
1360
0
                                          dset_contig->sieve_size, dset_contig->sieve_buf) < 0)
1361
0
                    HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed");
1362
0
            } /* end if */
1363
1364
            /* Grab the data out of the buffer (must be first piece of data in buffer ) */
1365
0
            H5MM_memcpy(dset_contig->sieve_buf, buf, len);
1366
1367
            /* Set sieve buffer dirty flag */
1368
0
            dset_contig->sieve_dirty = true;
1369
1370
            /* Stash local copies of these values */
1371
0
            sieve_start = dset_contig->sieve_loc;
1372
0
            sieve_size  = dset_contig->sieve_size;
1373
0
            sieve_end   = sieve_start + sieve_size;
1374
0
        } /* end else */
1375
0
    }     /* end if */
1376
0
    else {
1377
        /* Compute end of sequence to retrieve */
1378
0
        contig_end = addr + len - 1;
1379
1380
        /* If entire write is within the sieve buffer, write it to the buffer */
1381
0
        if (addr >= sieve_start && contig_end < sieve_end) {
1382
0
            unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start);
1383
1384
            /* Put the data into the sieve buffer */
1385
0
            H5MM_memcpy(base_sieve_buf, buf, len);
1386
1387
            /* Set sieve buffer dirty flag */
1388
0
            dset_contig->sieve_dirty = true;
1389
0
        } /* end if */
1390
        /* Entire request is not within this data sieve buffer */
1391
0
        else {
1392
            /* Check if we can actually hold the I/O request in the sieve buffer */
1393
0
            if (len > dset_contig->sieve_buf_size) {
1394
                /* Check for any overlap with the current sieve buffer */
1395
0
                if ((sieve_start >= addr && sieve_start < (contig_end + 1)) ||
1396
0
                    ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) {
1397
                    /* Flush the sieve buffer, if it's dirty */
1398
0
                    if (dset_contig->sieve_dirty) {
1399
                        /* Write to file */
1400
0
                        if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, sieve_start, sieve_size,
1401
0
                                                   dset_contig->sieve_buf) < 0)
1402
0
                            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed");
1403
1404
                        /* Reset sieve buffer dirty flag */
1405
0
                        dset_contig->sieve_dirty = false;
1406
0
                    } /* end if */
1407
1408
                    /* Force the sieve buffer to be re-read the next time */
1409
0
                    dset_contig->sieve_loc  = HADDR_UNDEF;
1410
0
                    dset_contig->sieve_size = 0;
1411
0
                } /* end if */
1412
1413
                /* Write directly from the user's buffer */
1414
0
                if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, addr, len, buf) < 0)
1415
0
                    HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed");
1416
0
            } /* end if */
1417
            /* Element size fits within the buffer size */
1418
0
            else {
1419
                /* Check if it is possible to (exactly) prepend or append to existing (dirty) sieve buffer */
1420
0
                if (((addr + len) == sieve_start || addr == sieve_end) &&
1421
0
                    (len + sieve_size) <= dset_contig->sieve_buf_size && dset_contig->sieve_dirty) {
1422
                    /* Prepend to existing sieve buffer */
1423
0
                    if ((addr + len) == sieve_start) {
1424
                        /* Move existing sieve information to correct location */
1425
0
                        memmove(dset_contig->sieve_buf + len, dset_contig->sieve_buf,
1426
0
                                dset_contig->sieve_size);
1427
1428
                        /* Copy in new information (must be first in sieve buffer) */
1429
0
                        H5MM_memcpy(dset_contig->sieve_buf, buf, len);
1430
1431
                        /* Adjust sieve location */
1432
0
                        dset_contig->sieve_loc = addr;
1433
1434
0
                    } /* end if */
1435
                    /* Append to existing sieve buffer */
1436
0
                    else {
1437
                        /* Copy in new information */
1438
0
                        H5MM_memcpy(dset_contig->sieve_buf + sieve_size, buf, len);
1439
0
                    } /* end else */
1440
1441
                    /* Adjust sieve size */
1442
0
                    dset_contig->sieve_size += len;
1443
0
                } /* end if */
1444
                /* Can't add the new data onto the existing sieve buffer */
1445
0
                else {
1446
                    /* Flush the sieve buffer if it's dirty */
1447
0
                    if (dset_contig->sieve_dirty) {
1448
                        /* Write to file */
1449
0
                        if (H5F_shared_block_write(f_sh, H5FD_MEM_DRAW, sieve_start, sieve_size,
1450
0
                                                   dset_contig->sieve_buf) < 0)
1451
0
                            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed");
1452
1453
                        /* Reset sieve buffer dirty flag */
1454
0
                        dset_contig->sieve_dirty = false;
1455
0
                    } /* end if */
1456
1457
                    /* Determine the new sieve buffer size & location */
1458
0
                    dset_contig->sieve_loc = addr;
1459
1460
                    /* Make certain we don't read off the end of the file */
1461
0
                    if (HADDR_UNDEF == (rel_eoa = H5F_shared_get_eoa(f_sh, H5FD_MEM_DRAW)))
1462
0
                        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size");
1463
1464
                    /* Only need this when resizing sieve buffer */
1465
0
                    max_data = store_contig->dset_size - dst_off;
1466
1467
                    /* Compute the size of the sieve buffer.
1468
                     * Don't read off the end of the file, don't read past
1469
                     * the end of the data element, and don't read more than
1470
                     * the buffer size.
1471
                     */
1472
0
                    min = MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size);
1473
0
                    H5_CHECKED_ASSIGN(dset_contig->sieve_size, size_t, min, hsize_t);
1474
1475
                    /* Check if there is any point in reading the data from the file */
1476
0
                    if (dset_contig->sieve_size > len) {
1477
                        /* Read the new sieve buffer */
1478
0
                        if (H5F_shared_block_read(f_sh, H5FD_MEM_DRAW, dset_contig->sieve_loc,
1479
0
                                                  dset_contig->sieve_size, dset_contig->sieve_buf) < 0)
1480
0
                            HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed");
1481
0
                    } /* end if */
1482
1483
                    /* Grab the data out of the buffer (must be first piece of data in buffer ) */
1484
0
                    H5MM_memcpy(dset_contig->sieve_buf, buf, len);
1485
1486
                    /* Set sieve buffer dirty flag */
1487
0
                    dset_contig->sieve_dirty = true;
1488
0
                } /* end else */
1489
0
            }     /* end else */
1490
0
        }         /* end else */
1491
0
    }             /* end else */
1492
1493
0
done:
1494
0
    FUNC_LEAVE_NOAPI(ret_value)
1495
0
} /* end H5D__contig_writevv_sieve_cb() */
1496
1497
/*-------------------------------------------------------------------------
1498
 * Function:  H5D__contig_writevv_cb
1499
 *
1500
 * Purpose: Callback operator for H5D__contig_writevv().
1501
 *
1502
 * Return:  Non-negative on success/Negative on failure
1503
 *
1504
 *-------------------------------------------------------------------------
1505
 */
1506
static herr_t
1507
H5D__contig_writevv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata)
1508
0
{
1509
0
    H5D_contig_writevv_ud_t *udata =
1510
0
        (H5D_contig_writevv_ud_t *)_udata; /* User data for H5VM_opvv() operator */
1511
0
    herr_t ret_value = SUCCEED;            /* Return value */
1512
1513
0
    FUNC_ENTER_PACKAGE
1514
1515
    /* Write data */
1516
0
    if (H5F_shared_block_write(udata->f_sh, H5FD_MEM_DRAW, (udata->dset_addr + dst_off), len,
1517
0
                               (udata->wbuf + src_off)) < 0)
1518
0
        HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed");
1519
1520
0
done:
1521
0
    FUNC_LEAVE_NOAPI(ret_value)
1522
0
} /* end H5D__contig_writevv_cb() */
1523
1524
/*-------------------------------------------------------------------------
1525
 * Function:  H5D__contig_writevv
1526
 *
1527
 * Purpose: Writes some data vectors into a dataset from vectors into a
1528
 *              buffer.  The address is the start of the dataset,
1529
 *              relative to the base address for the file and the offsets and
1530
 *              sequence lengths are in bytes.
1531
 *
1532
 * Return:  Non-negative on success/Negative on failure
1533
 *
1534
 * Notes:
1535
 *      Offsets in the sequences must be monotonically increasing
1536
 *
1537
 *-------------------------------------------------------------------------
1538
 */
1539
static ssize_t
1540
H5D__contig_writevv(const H5D_io_info_t *io_info, const H5D_dset_io_info_t *dset_info, size_t dset_max_nseq,
1541
                    size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq,
1542
                    size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[])
1543
0
{
1544
0
    ssize_t ret_value = -1; /* Return value (Size of sequence in bytes) */
1545
1546
0
    FUNC_ENTER_PACKAGE
1547
1548
    /* Check args */
1549
0
    assert(io_info);
1550
0
    assert(dset_info);
1551
0
    assert(dset_curr_seq);
1552
0
    assert(dset_len_arr);
1553
0
    assert(dset_off_arr);
1554
0
    assert(mem_curr_seq);
1555
0
    assert(mem_len_arr);
1556
0
    assert(mem_off_arr);
1557
1558
    /* Check if data sieving is enabled */
1559
0
    if (H5F_SHARED_HAS_FEATURE(io_info->f_sh, H5FD_FEAT_DATA_SIEVE)) {
1560
0
        H5D_contig_writevv_sieve_ud_t udata; /* User data for H5VM_opvv() operator */
1561
1562
        /* Set up user data for H5VM_opvv() */
1563
0
        udata.f_sh         = io_info->f_sh;
1564
0
        udata.dset_contig  = &(dset_info->dset->shared->cache.contig);
1565
0
        udata.store_contig = &(dset_info->store->contig);
1566
0
        udata.wbuf         = (const unsigned char *)dset_info->buf.cvp;
1567
1568
        /* Call generic sequence operation routine */
1569
0
        if ((ret_value =
1570
0
                 H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq,
1571
0
                           mem_curr_seq, mem_len_arr, mem_off_arr, H5D__contig_writevv_sieve_cb, &udata)) < 0)
1572
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized sieve buffer write");
1573
0
    } /* end if */
1574
0
    else {
1575
0
        H5D_contig_writevv_ud_t udata; /* User data for H5VM_opvv() operator */
1576
1577
        /* Set up user data for H5VM_opvv() */
1578
0
        udata.f_sh      = io_info->f_sh;
1579
0
        udata.dset_addr = dset_info->store->contig.dset_addr;
1580
0
        udata.wbuf      = (const unsigned char *)dset_info->buf.cvp;
1581
1582
        /* Call generic sequence operation routine */
1583
0
        if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, mem_max_nseq,
1584
0
                                   mem_curr_seq, mem_len_arr, mem_off_arr, H5D__contig_writevv_cb, &udata)) <
1585
0
            0)
1586
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized read");
1587
0
    } /* end else */
1588
1589
0
done:
1590
0
    FUNC_LEAVE_NOAPI(ret_value)
1591
0
} /* end H5D__contig_writevv() */
1592
1593
/*-------------------------------------------------------------------------
1594
 * Function:  H5D__contig_flush
1595
 *
1596
 * Purpose: Writes all dirty data to disk.
1597
 *
1598
 * Return:  Non-negative on success/Negative on failure
1599
 *
1600
 *-------------------------------------------------------------------------
1601
 */
1602
static herr_t
1603
H5D__contig_flush(H5D_t *dset)
1604
5
{
1605
5
    herr_t ret_value = SUCCEED; /* Return value */
1606
1607
5
    FUNC_ENTER_PACKAGE
1608
1609
    /* Sanity check */
1610
5
    assert(dset);
1611
1612
    /* Flush any data in sieve buffer */
1613
5
    if (H5D__flush_sieve_buf(dset) < 0)
1614
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to flush sieve buffer");
1615
1616
5
done:
1617
5
    FUNC_LEAVE_NOAPI(ret_value)
1618
5
} /* end H5D__contig_flush() */
1619
1620
/*-------------------------------------------------------------------------
1621
 * Function:    H5D__contig_io_term
1622
 *
1623
 * Purpose:    Destroy I/O operation information.
1624
 *
1625
 * Return:    Non-negative on success/Negative on failure
1626
 *
1627
 *-------------------------------------------------------------------------
1628
 */
1629
static herr_t
1630
H5D__contig_io_term(H5D_io_info_t H5_ATTR_UNUSED *io_info, H5D_dset_io_info_t *di)
1631
0
{
1632
0
    herr_t ret_value = SUCCEED; /*return value        */
1633
1634
0
    FUNC_ENTER_PACKAGE
1635
1636
0
    assert(di);
1637
1638
    /* Free piece info */
1639
0
    if (di->layout_io_info.contig_piece_info) {
1640
0
        if (H5D__free_piece_info(di->layout_io_info.contig_piece_info, NULL, NULL) < 0)
1641
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't free piece info");
1642
0
        di->layout_io_info.contig_piece_info = NULL;
1643
0
    }
1644
1645
0
done:
1646
0
    FUNC_LEAVE_NOAPI(ret_value)
1647
0
} /* end H5D__contig_io_term() */
1648
1649
/*-------------------------------------------------------------------------
1650
 * Function:  H5D__contig_copy
1651
 *
1652
 * Purpose: Copy contiguous storage raw data from SRC file to DST file.
1653
 *
1654
 * Return:  Non-negative on success, negative on failure.
1655
 *
1656
 *-------------------------------------------------------------------------
1657
 */
1658
herr_t
1659
H5D__contig_copy(H5F_t *f_src, const H5O_storage_contig_t *storage_src, H5F_t *f_dst,
1660
                 H5O_storage_contig_t *storage_dst, H5T_t *dt_src, H5O_copy_t *cpy_info)
1661
0
{
1662
0
    haddr_t       addr_src;                                    /* File offset in source dataset */
1663
0
    haddr_t       addr_dst;                                    /* File offset in destination dataset */
1664
0
    H5T_path_t   *tpath_src_mem = NULL, *tpath_mem_dst = NULL; /* Datatype conversion paths */
1665
0
    H5T_t        *dt_dst      = NULL;                          /* Destination datatype */
1666
0
    H5T_t        *dt_mem      = NULL;                          /* Memory datatype */
1667
0
    size_t        src_dt_size = 0;                             /* Source datatype size */
1668
0
    size_t        mem_dt_size = 0;                             /* Memory datatype size */
1669
0
    size_t        dst_dt_size = 0;                             /* Destination datatype size */
1670
0
    size_t        max_dt_size;                                 /* Max. datatype size */
1671
0
    size_t        nelmts = 0;                                  /* Number of elements in buffer */
1672
0
    size_t        src_nbytes;                                  /* Number of bytes to read from source */
1673
0
    size_t        mem_nbytes;                                  /* Number of bytes to convert in memory */
1674
0
    size_t        dst_nbytes;                                  /* Number of bytes to write to destination */
1675
0
    hsize_t       total_src_nbytes;                            /* Total number of bytes to copy */
1676
0
    size_t        buf_size;                                    /* Size of copy buffer */
1677
0
    void         *buf         = NULL;                          /* Buffer for copying data */
1678
0
    void         *bkg         = NULL;                          /* Temporary buffer for copying data */
1679
0
    void         *reclaim_buf = NULL;                          /* Buffer for reclaiming data */
1680
0
    H5S_t        *buf_space   = NULL;                          /* Dataspace describing buffer */
1681
0
    hsize_t       buf_dim[1]  = {0};                           /* Dimension for buffer */
1682
0
    bool          is_vlen     = false; /* Flag to indicate that VL type conversion should occur */
1683
0
    bool          fix_ref     = false; /* Flag to indicate that ref values should be fixed */
1684
0
    H5D_shared_t *shared_fo =
1685
0
        (H5D_shared_t *)cpy_info->shared_fo; /* Pointer to the shared struct for dataset object */
1686
0
    bool    try_sieve   = false;             /* Try to get data from the sieve buffer */
1687
0
    haddr_t sieve_start = HADDR_UNDEF;       /* Start location of sieve buffer */
1688
0
    haddr_t sieve_end   = HADDR_UNDEF;       /* End locations of sieve buffer */
1689
0
    herr_t  ret_value   = SUCCEED;           /* Return value */
1690
1691
0
    FUNC_ENTER_PACKAGE
1692
1693
    /* Check args */
1694
0
    assert(f_src);
1695
0
    assert(storage_src);
1696
0
    assert(f_dst);
1697
0
    assert(storage_dst);
1698
0
    assert(dt_src);
1699
1700
    /* Allocate space for destination raw data */
1701
0
    if (H5D__contig_alloc(f_dst, storage_dst) < 0)
1702
0
        HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "unable to allocate contiguous storage");
1703
1704
    /* Set up number of bytes to copy, and initial buffer size */
1705
    /* (actually use the destination size, which has been fixed up, if necessary) */
1706
0
    total_src_nbytes = storage_dst->size;
1707
0
    H5_CHECK_OVERFLOW(total_src_nbytes, hsize_t, size_t);
1708
0
    buf_size = MIN(H5D_TEMP_BUF_SIZE, (size_t)total_src_nbytes);
1709
1710
    /* If there's a VLEN source datatype, set up type conversion information */
1711
0
    if (H5T_detect_class(dt_src, H5T_VLEN, false) > 0) {
1712
        /* create a memory copy of the variable-length datatype */
1713
0
        if (NULL == (dt_mem = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
1714
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy");
1715
1716
        /* create variable-length datatype at the destination file */
1717
0
        if (NULL == (dt_dst = H5T_copy(dt_src, H5T_COPY_TRANSIENT)))
1718
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to copy");
1719
0
        if (H5T_set_loc(dt_dst, H5F_VOL_OBJ(f_dst), H5T_LOC_DISK) < 0) {
1720
0
            (void)H5T_close_real(dt_dst);
1721
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "cannot mark datatype on disk");
1722
0
        } /* end if */
1723
1724
        /* Set up the conversion functions */
1725
0
        if (NULL == (tpath_src_mem = H5T_path_find(dt_src, dt_mem)))
1726
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between src and mem datatypes");
1727
0
        if (NULL == (tpath_mem_dst = H5T_path_find(dt_mem, dt_dst)))
1728
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between mem and dst datatypes");
1729
1730
        /* Determine largest datatype size */
1731
0
        if (0 == (src_dt_size = H5T_get_size(dt_src)))
1732
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size");
1733
0
        if (0 == (mem_dt_size = H5T_get_size(dt_mem)))
1734
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size");
1735
0
        max_dt_size = MAX(src_dt_size, mem_dt_size);
1736
0
        if (0 == (dst_dt_size = H5T_get_size(dt_dst)))
1737
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to determine datatype size");
1738
0
        max_dt_size = MAX(max_dt_size, dst_dt_size);
1739
1740
        /* Set maximum number of whole elements that fit in buffer */
1741
0
        if (0 == (nelmts = buf_size / max_dt_size))
1742
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "element size too large");
1743
1744
        /* Set the number of bytes to transfer */
1745
0
        src_nbytes = nelmts * src_dt_size;
1746
0
        dst_nbytes = nelmts * dst_dt_size;
1747
0
        mem_nbytes = nelmts * mem_dt_size;
1748
1749
        /* Adjust buffer size to be multiple of elements */
1750
0
        buf_size = nelmts * max_dt_size;
1751
1752
        /* Create dataspace for number of elements in buffer */
1753
0
        buf_dim[0] = nelmts;
1754
1755
        /* Create the space and set the initial extent */
1756
0
        if (NULL == (buf_space = H5S_create_simple((unsigned)1, buf_dim, NULL)))
1757
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace");
1758
1759
        /* Set flag to do type conversion */
1760
0
        is_vlen = true;
1761
0
    } /* end if */
1762
0
    else {
1763
        /* Check for reference datatype */
1764
0
        if (H5T_get_class(dt_src, false) == H5T_REFERENCE) {
1765
            /* Need to fix values of references when copying across files */
1766
0
            if (f_src != f_dst)
1767
0
                fix_ref = true;
1768
0
        } /* end if */
1769
1770
        /* Set the number of bytes to read & write to the buffer size */
1771
0
        src_nbytes = dst_nbytes = mem_nbytes = buf_size;
1772
0
    } /* end else */
1773
1774
    /* Allocate space for copy buffer */
1775
0
    assert(buf_size);
1776
0
    if (NULL == (buf = H5FL_BLK_MALLOC(type_conv, buf_size)))
1777
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for copy buffer");
1778
1779
    /* Need extra buffer for datatype conversions, to prevent stranding/leaking memory */
1780
0
    if (is_vlen || fix_ref) {
1781
0
        if (NULL == (reclaim_buf = H5FL_BLK_MALLOC(type_conv, buf_size)))
1782
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for copy buffer");
1783
1784
        /* allocate temporary bkg buff for data conversion */
1785
0
        if (NULL == (bkg = H5FL_BLK_MALLOC(type_conv, buf_size)))
1786
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for copy buffer");
1787
0
    } /* end if */
1788
1789
    /* Loop over copying data */
1790
0
    addr_src = storage_src->addr;
1791
0
    addr_dst = storage_dst->addr;
1792
1793
    /* If data sieving is enabled and the dataset is open in the file,
1794
       set up to copy data out of the sieve buffer if deemed possible later */
1795
0
    if (H5F_HAS_FEATURE(f_src, H5FD_FEAT_DATA_SIEVE) && shared_fo && shared_fo->cache.contig.sieve_buf) {
1796
0
        try_sieve   = true;
1797
0
        sieve_start = shared_fo->cache.contig.sieve_loc;
1798
0
        sieve_end   = sieve_start + shared_fo->cache.contig.sieve_size;
1799
0
    }
1800
1801
0
    while (total_src_nbytes > 0) {
1802
        /* Check if we should reduce the number of bytes to transfer */
1803
0
        if (total_src_nbytes < src_nbytes) {
1804
            /* Adjust bytes to transfer */
1805
0
            src_nbytes = (size_t)total_src_nbytes;
1806
1807
            /* Adjust dataspace describing buffer */
1808
0
            if (is_vlen) {
1809
                /* Adjust destination & memory bytes to transfer */
1810
0
                nelmts     = src_nbytes / src_dt_size;
1811
0
                dst_nbytes = nelmts * dst_dt_size;
1812
0
                mem_nbytes = nelmts * mem_dt_size;
1813
1814
                /* Adjust size of buffer's dataspace dimension */
1815
0
                buf_dim[0] = nelmts;
1816
1817
                /* Adjust size of buffer's dataspace */
1818
0
                if (H5S_set_extent_real(buf_space, buf_dim) < 0)
1819
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "unable to change buffer dataspace size");
1820
0
            } /* end if */
1821
0
            else
1822
                /* Adjust destination & memory bytes to transfer */
1823
0
                dst_nbytes = mem_nbytes = src_nbytes;
1824
0
        } /* end if */
1825
1826
        /* If the entire copy is within the sieve buffer, copy data from the sieve buffer */
1827
0
        if (try_sieve && (addr_src >= sieve_start) && ((addr_src + src_nbytes - 1) < sieve_end)) {
1828
0
            unsigned char *base_sieve_buf = shared_fo->cache.contig.sieve_buf + (addr_src - sieve_start);
1829
1830
0
            H5MM_memcpy(buf, base_sieve_buf, src_nbytes);
1831
0
        }
1832
0
        else
1833
            /* Read raw data from source file */
1834
0
            if (H5F_block_read(f_src, H5FD_MEM_DRAW, addr_src, src_nbytes, buf) < 0)
1835
0
                HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read raw data");
1836
1837
        /* Perform datatype conversion, if necessary */
1838
0
        if (is_vlen) {
1839
            /* Convert from source file to memory */
1840
0
            if (H5T_convert(tpath_src_mem, dt_src, dt_mem, nelmts, (size_t)0, (size_t)0, buf, bkg) < 0)
1841
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "datatype conversion failed");
1842
1843
            /* Copy into another buffer, to reclaim memory later */
1844
0
            H5MM_memcpy(reclaim_buf, buf, mem_nbytes);
1845
1846
            /* Set background buffer to all zeros */
1847
0
            memset(bkg, 0, buf_size);
1848
1849
            /* Convert from memory to destination file */
1850
0
            if (H5T_convert(tpath_mem_dst, dt_mem, dt_dst, nelmts, (size_t)0, (size_t)0, buf, bkg) < 0)
1851
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "datatype conversion failed");
1852
1853
            /* Reclaim space from variable length data */
1854
0
            if (H5T_reclaim(dt_mem, buf_space, reclaim_buf) < 0)
1855
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reclaim variable-length data");
1856
0
        } /* end if */
1857
0
        else if (fix_ref) {
1858
            /* Check for expanding references */
1859
0
            if (cpy_info->expand_ref) {
1860
                /* Copy the reference elements */
1861
0
                if (H5O_copy_expand_ref(f_src, dt_src, buf, buf_size, f_dst, bkg, cpy_info) < 0)
1862
0
                    HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "unable to copy reference attribute");
1863
1864
                /* After fix ref, copy the new reference elements to the buffer to write out */
1865
0
                H5MM_memcpy(buf, bkg, buf_size);
1866
0
            } /* end if */
1867
0
            else
1868
                /* Reset value to zero */
1869
0
                memset(buf, 0, src_nbytes);
1870
0
        } /* end if */
1871
1872
        /* Write raw data to destination file */
1873
0
        if (H5F_block_write(f_dst, H5FD_MEM_DRAW, addr_dst, dst_nbytes, buf) < 0)
1874
0
            HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write raw data");
1875
1876
        /* Adjust loop variables */
1877
0
        addr_src += src_nbytes;
1878
0
        addr_dst += dst_nbytes;
1879
0
        total_src_nbytes -= src_nbytes;
1880
0
    } /* end while */
1881
1882
0
done:
1883
0
    if (dt_dst && (H5T_close(dt_dst) < 0))
1884
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close temporary datatype");
1885
0
    if (dt_mem && (H5T_close(dt_mem) < 0))
1886
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close temporary datatype");
1887
0
    if (buf_space && H5S_close(buf_space) < 0)
1888
0
        HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close temporary dataspace");
1889
0
    if (buf)
1890
0
        buf = H5FL_BLK_FREE(type_conv, buf);
1891
0
    if (reclaim_buf)
1892
0
        reclaim_buf = H5FL_BLK_FREE(type_conv, reclaim_buf);
1893
0
    if (bkg)
1894
0
        bkg = H5FL_BLK_FREE(type_conv, bkg);
1895
1896
0
    FUNC_LEAVE_NOAPI(ret_value)
1897
0
} /* end H5D__contig_copy() */