Coverage Report

Created: 2025-08-03 06:26

/src/hdf5/src/H5Oflush.c
Line
Count
Source (jump to first uncovered line)
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
 *
15
 * Created:     H5Oflush.c
16
 *
17
 * Purpose:     Object flush/refresh routines.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5Omodule.h" /* This source code file is part of the H5O module */
27
#define H5T_FRIEND     /* Suppress error about including H5Tpkg */
28
29
/***********/
30
/* Headers */
31
/***********/
32
33
#include "H5private.h"   /* Generic Functions */
34
#include "H5CXprivate.h" /* API Contexts */
35
#include "H5Dprivate.h"  /* Datasets */
36
#include "H5Eprivate.h"  /* Errors   */
37
#include "H5Fprivate.h"  /* Files    */
38
#include "H5Gprivate.h"  /* Groups   */
39
#include "H5Iprivate.h"  /* IDs      */
40
#include "H5Opkg.h"      /* Objects  */
41
#include "H5Tpkg.h"      /* Datatypes */
42
43
/********************/
44
/* Local Prototypes */
45
/********************/
46
static herr_t H5O__oh_tag(const H5O_loc_t *oloc, haddr_t *tag);
47
static herr_t H5O__refresh_metadata_close(H5O_loc_t *oloc, H5G_loc_t *obj_loc, hid_t oid);
48
49
/*************/
50
/* Functions */
51
/*************/
52
53
/*-------------------------------------------------------------------------
54
 * Function:    H5O_flush
55
 *
56
 * Purpose:     Internal routine to flush an object
57
 *
58
 * Return:  Success:  Non-negative
59
 *    Failure:  Negative
60
 *
61
 *-------------------------------------------------------------------------
62
 */
63
herr_t
64
H5O_flush(H5O_loc_t *oloc, hid_t obj_id)
65
0
{
66
0
    void                  *obj_ptr;             /* Pointer to object */
67
0
    const H5O_obj_class_t *obj_class;           /* Class of object */
68
0
    herr_t                 ret_value = SUCCEED; /* Return value */
69
70
0
    FUNC_ENTER_NOAPI(FAIL)
71
72
    /* Currently, H5Oflush causes H5Fclose to trigger an assertion failure in metadata cache.
73
     * Leave this situation for the future solution */
74
0
    if (H5F_HAS_FEATURE(oloc->file, H5FD_FEAT_HAS_MPI))
75
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "H5Oflush isn't supported for parallel");
76
77
    /* Get the object pointer */
78
0
    if (NULL == (obj_ptr = H5VL_object(obj_id)))
79
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier");
80
81
    /* Get the object class */
82
0
    if (NULL == (obj_class = H5O__obj_class(oloc)))
83
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object class");
84
85
    /* Flush the object of this class */
86
0
    if (obj_class->flush && obj_class->flush(obj_ptr) < 0)
87
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object");
88
89
    /* Flush the object metadata and invoke flush callback */
90
0
    if (H5O_flush_common(oloc, obj_id) < 0)
91
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object and object flush callback");
92
93
0
done:
94
0
    FUNC_LEAVE_NOAPI(ret_value)
95
0
} /* end H5O_flush() */
96
97
/*-------------------------------------------------------------------------
98
 * Function:    H5O_flush_common
99
 *
100
 * Purpose:     Flushes the object's metadata
101
 *    Invokes the user-defined callback if there is one.
102
 *
103
 * Return:    Non-negative on success, negative on failure
104
 *
105
 *-------------------------------------------------------------------------
106
 */
107
herr_t
108
H5O_flush_common(H5O_loc_t *oloc, hid_t obj_id)
109
0
{
110
0
    haddr_t tag       = 0;
111
0
    herr_t  ret_value = SUCCEED; /* Return value */
112
113
0
    FUNC_ENTER_NOAPI(FAIL)
114
115
    /* Retrieve tag for object */
116
0
    if (H5O__oh_tag(oloc, &tag) < 0)
117
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object metadata");
118
119
    /* Flush metadata based on tag value of the object */
120
0
    if (H5F_flush_tagged_metadata(oloc->file, tag) < 0)
121
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata");
122
123
    /* Check to invoke callback */
124
0
    if (H5F_object_flush_cb(oloc->file, obj_id) < 0)
125
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to do object flush callback");
126
127
0
done:
128
0
    FUNC_LEAVE_NOAPI(ret_value)
129
0
} /* end H5O_flush_common() */
130
131
/*-------------------------------------------------------------------------
132
 * Function:    H5O__oh_tag
133
 *
134
 * Purpose:     Get object header's address--tag value for the object
135
 *
136
 * Return:    Success:    Non-negative
137
 *            Failure:    Negative
138
 *
139
 *-------------------------------------------------------------------------
140
 */
141
static herr_t
142
H5O__oh_tag(const H5O_loc_t *oloc, haddr_t *tag)
143
0
{
144
0
    H5O_t *oh        = NULL;    /* Object header */
145
0
    herr_t ret_value = SUCCEED; /* Return value */
146
147
0
    FUNC_ENTER_PACKAGE
148
149
    /* Check args */
150
0
    assert(oloc);
151
152
    /* Get object header for object */
153
0
    if (NULL == (oh = H5O_protect(oloc, H5AC__READ_ONLY_FLAG, false)))
154
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object's object header");
155
156
    /* Get object header's address (i.e. the tag value for this object) */
157
0
    if (HADDR_UNDEF == (*tag = H5O_OH_GET_ADDR(oh)))
158
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get address of object header");
159
160
0
done:
161
    /* Unprotect object header on failure */
162
0
    if (oh && H5O_unprotect(oloc, oh, H5AC__NO_FLAGS_SET) < 0)
163
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
164
165
0
    FUNC_LEAVE_NOAPI(ret_value)
166
0
} /* end H5O__oh_tag() */
167
168
/*-------------------------------------------------------------------------
169
 * Function:    H5O_refresh_metadata
170
 *
171
 * Purpose:     Refreshes all buffers associated with an object.
172
 *
173
 * Note:  This is based on the original H5O_refresh_metadata() but
174
 *          is split into 2 routines.
175
 *          This is done so that H5Fstart_swmr_write() can use these
176
 *          2 routines to refresh opened objects.  This may be
177
 *          restored back to the original code when H5Fstart_swmr_write()
178
 *          uses a different approach to handle issues with opened objects.
179
 *    H5Fstart_swmr_write() no longer calls the 1st routine.  (12/24/15)
180
 *
181
 * Return:      Non-negative on success, negative on failure
182
 *
183
 *-------------------------------------------------------------------------
184
 */
185
herr_t
186
H5O_refresh_metadata(H5O_loc_t *oloc, hid_t oid)
187
0
{
188
0
    H5VL_object_t *vol_obj   = NULL;  /* VOL object associated with the ID */
189
0
    bool           objs_incr = false; /* Whether the object count in the file was incremented */
190
0
    H5F_t         *file      = NULL;
191
0
    herr_t         ret_value = SUCCEED; /* Return value */
192
193
0
    FUNC_ENTER_NOAPI(FAIL)
194
195
    /* If the file is opened with write access, no need to perform refresh actions. */
196
0
    if (!(H5F_INTENT(oloc->file) & H5F_ACC_RDWR)) {
197
0
        H5G_loc_t         obj_loc;
198
0
        H5O_loc_t         obj_oloc;
199
0
        H5G_name_t        obj_path;
200
0
        H5O_shared_t      cached_H5O_shared;
201
0
        H5VL_connector_t *connector = NULL;
202
203
        /* Hold a copy of the object's file pointer, since closing the object will
204
         * invalidate the file pointer in the oloc.
205
         */
206
0
        file = oloc->file;
207
208
        /* Create empty object location */
209
0
        obj_loc.oloc = &obj_oloc;
210
0
        obj_loc.path = &obj_path;
211
0
        H5G_loc_reset(&obj_loc);
212
213
        /* "Fake" another open object in the file, so that it doesn't get closed
214
         *  if this object is the only thing holding the file open.
215
         */
216
0
        H5F_incr_nopen_objs(oloc->file);
217
0
        objs_incr = true;
218
219
        /* Save important datatype state */
220
0
        if (H5I_get_type(oid) == H5I_DATATYPE)
221
0
            if (H5T_save_refresh_state(oid, &cached_H5O_shared) < 0)
222
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to save datatype state");
223
224
        /* Get the VOL object from the ID and cache a pointer to the connector.
225
         * The vol_obj will disappear when the underlying object is closed, so
226
         * we can't use that directly.
227
         */
228
0
        if (NULL == (vol_obj = H5VL_vol_object(oid)))
229
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier");
230
0
        connector = H5VL_OBJ_CONNECTOR(vol_obj);
231
232
        /* Bump the number of references on the VOL connector.
233
         * If you don't do this, VDS refreshes can accidentally close the connector.
234
         */
235
0
        H5VL_conn_inc_rc(connector);
236
237
        /* Close object & evict its metadata */
238
0
        if (H5O__refresh_metadata_close(oloc, &obj_loc, oid) < 0) {
239
0
            H5VL_conn_dec_rc(connector);
240
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object");
241
0
        }
242
243
        /* Re-open the object, re-fetching its metadata */
244
0
        if (H5O_refresh_metadata_reopen(oid, H5P_DEFAULT, &obj_loc, connector, false) < 0) {
245
0
            H5VL_conn_dec_rc(connector);
246
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object");
247
0
        }
248
249
        /* Restore the number of references on the VOL connector */
250
0
        if (H5VL_conn_dec_rc(connector) < 0)
251
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "can't decrement reference count for connector");
252
253
        /* Restore important datatype state */
254
0
        if (H5I_get_type(oid) == H5I_DATATYPE)
255
0
            if (H5T_restore_refresh_state(oid, &cached_H5O_shared) < 0)
256
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to restore datatype state");
257
258
0
    } /* end if */
259
260
0
done:
261
0
    if (objs_incr && file)
262
0
        H5F_decr_nopen_objs(file);
263
264
0
    FUNC_LEAVE_NOAPI(ret_value)
265
0
} /* end H5O_refresh_metadata() */
266
267
/*-------------------------------------------------------------------------
268
 * Function:    H5O__refresh_metadata_close
269
 *
270
 * Purpose:     This is the first part of the original routine H5O_refresh_metadata().
271
 *    (1) Save object location information.
272
 *    (2) Handle multiple dataset opens
273
 *    (3) Get object cork status
274
 *    (4) Close the object
275
 *    (5) Flush and evict object metadata
276
 *    (6) Re-cork the object if needed
277
 *
278
 * Return:  Success:    Non-negative
279
 *          Failure:    Negative
280
 *
281
 *-------------------------------------------------------------------------
282
 */
283
static herr_t
284
H5O__refresh_metadata_close(H5O_loc_t *oloc, H5G_loc_t *obj_loc, hid_t oid)
285
0
{
286
0
    H5F_t  *file;                /* Local copy of the object's file pointer */
287
0
    haddr_t tag       = 0;       /* Tag for object */
288
0
    bool    corked    = false;   /* Whether object's metadata is corked */
289
0
    herr_t  ret_value = SUCCEED; /* Return value */
290
291
0
    FUNC_ENTER_PACKAGE
292
293
    /* Make deep local copy of object's location information */
294
0
    if (obj_loc) {
295
0
        H5G_loc_t tmp_loc;
296
297
0
        H5G_loc(oid, &tmp_loc);
298
0
        H5G_loc_copy(obj_loc, &tmp_loc, H5_COPY_DEEP);
299
0
    } /* end if */
300
301
    /* Handle close for multiple dataset opens */
302
0
    if (H5I_get_type(oid) == H5I_DATASET)
303
0
        if (H5D_mult_refresh_close(oid) < 0)
304
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to prepare refresh for dataset");
305
306
    /* Retrieve tag for object */
307
0
    if (H5O__oh_tag(oloc, &tag) < 0)
308
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to get object header address");
309
310
    /* Get cork status of the object with tag */
311
0
    if (H5AC_cork(oloc->file, tag, H5AC__GET_CORKED, &corked) < 0)
312
0
        HGOTO_ERROR(H5E_OHDR, H5E_SYSTEM, FAIL, "unable to retrieve an object's cork status");
313
314
    /* Hold a copy of the object's file pointer, since closing the object will
315
     * invalidate the file pointer in the oloc.
316
     */
317
0
    file = oloc->file;
318
    /* Close the object */
319
0
    if (H5I_dec_ref(oid) < 0)
320
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to close object");
321
322
    /* Flush metadata based on tag value of the object */
323
0
    if (H5F_flush_tagged_metadata(file, tag) < 0)
324
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata");
325
326
    /* Evict the object's tagged metadata */
327
0
    if (H5AC_evict_tagged_metadata(file, tag, true) < 0)
328
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to evict metadata");
329
330
    /* Re-cork object with tag */
331
0
    if (corked)
332
0
        if (H5AC_cork(file, tag, H5AC__SET_CORK, &corked) < 0)
333
0
            HGOTO_ERROR(H5E_OHDR, H5E_SYSTEM, FAIL, "unable to cork the object");
334
335
0
done:
336
0
    FUNC_LEAVE_NOAPI(ret_value)
337
0
} /* end H5O__refresh_metadata_close() */
338
339
/*-------------------------------------------------------------------------
340
 * Function:    H5O_refresh_metadata_reopen
341
 *
342
 * Purpose:     This is the second part of the original routine H5O_refresh_metadata().
343
 *      (1) Re-open object with the saved object location information.
344
 *      (2) Re-register object ID with the re-opened object.
345
 *
346
 * Return:      SUCCEED/FAIL
347
 *
348
 *-------------------------------------------------------------------------
349
 */
350
herr_t
351
H5O_refresh_metadata_reopen(hid_t oid, hid_t apl_id, H5G_loc_t *obj_loc, H5VL_connector_t *vol_connector,
352
                            bool start_swmr)
353
0
{
354
0
    void      *object = NULL;       /* Object for this operation */
355
0
    H5I_type_t type;                /* Type of object for the ID */
356
0
    herr_t     ret_value = SUCCEED; /* Return value */
357
358
0
    FUNC_ENTER_NOAPI(FAIL)
359
360
    /* Sanity check */
361
0
    assert(obj_loc);
362
0
    assert(vol_connector);
363
364
    /* Get object's type */
365
0
    type = H5I_get_type(oid);
366
367
0
    switch (type) {
368
0
        case H5I_GROUP:
369
            /* Re-open the group */
370
0
            if (NULL == (object = H5G_open(obj_loc)))
371
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open group");
372
0
            break;
373
374
0
        case H5I_DATATYPE:
375
            /* Re-open the named datatype */
376
0
            if (NULL == (object = H5T_open(obj_loc)))
377
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open named datatype");
378
0
            break;
379
380
0
        case H5I_DATASET:
381
            /* Set dataset access property list in API context if appropriate */
382
0
            if (H5CX_set_apl(&apl_id, H5P_CLS_DACC, oid, true) < 0)
383
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access property list info");
384
385
            /* Re-open the dataset */
386
0
            if (NULL ==
387
0
                (object = H5D_open(obj_loc, apl_id == H5P_DEFAULT ? H5P_DATASET_ACCESS_DEFAULT : apl_id)))
388
0
                HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open dataset");
389
0
            if (!start_swmr) /* No need to handle multiple opens when H5Fstart_swmr_write() */
390
0
                if (H5D_mult_refresh_reopen((H5D_t *)object) < 0)
391
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to finish refresh for dataset");
392
0
            break;
393
394
0
        case H5I_MAP:
395
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "maps not supported in native VOL connector");
396
397
0
        case H5I_UNINIT:
398
0
        case H5I_BADID:
399
0
        case H5I_FILE:
400
0
        case H5I_DATASPACE:
401
0
        case H5I_ATTR:
402
0
        case H5I_VFL:
403
0
        case H5I_VOL:
404
0
        case H5I_GENPROP_CLS:
405
0
        case H5I_GENPROP_LST:
406
0
        case H5I_ERROR_CLASS:
407
0
        case H5I_ERROR_MSG:
408
0
        case H5I_ERROR_STACK:
409
0
        case H5I_SPACE_SEL_ITER:
410
0
        case H5I_EVENTSET:
411
0
        case H5I_NTYPES:
412
0
        default:
413
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL,
414
0
                        "not a valid file object ID (dataset, group, or datatype)");
415
0
            break;
416
0
    } /* end switch */
417
418
    /* Re-register ID for the object */
419
0
    if ((H5VL_register_using_existing_id(type, object, vol_connector, true, oid)) < 0)
420
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTREGISTER, FAIL, "unable to re-register object ID after refresh");
421
422
0
done:
423
0
    FUNC_LEAVE_NOAPI(ret_value)
424
0
} /* end H5O_refresh_metadata_reopen() */