1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /*-------------------------------------------------------------------------
15 *
16 * Created: H5Oflush.c
17 * Aug 19, 2010
18 * Mike McGreevy <mamcgree@hdfgroup.org>
19 *
20 * Purpose: Object flush/refresh routines.
21 *
22 *-------------------------------------------------------------------------
23 */
24
25 /****************/
26 /* Module Setup */
27 /****************/
28
29 #include "H5Omodule.h" /* This source code file is part of the H5O module */
30
31 /***********/
32 /* Headers */
33 /***********/
34
35 #include "H5private.h" /* Generic Functions */
36 #include "H5CXprivate.h" /* API Contexts */
37 #include "H5Dprivate.h" /* Datasets */
38 #include "H5Eprivate.h" /* Errors */
39 #include "H5Fprivate.h" /* Files */
40 #include "H5Gprivate.h" /* Groups */
41 #include "H5Iprivate.h" /* IDs */
42 #include "H5Opkg.h" /* Objects */
43
44
45 /********************/
46 /* Local Prototypes */
47 /********************/
48 static herr_t H5O__flush(hid_t obj_id);
49 static herr_t H5O__oh_tag(const H5O_loc_t *oloc, haddr_t *tag);
50 static herr_t H5O__refresh_metadata_close(hid_t oid, H5O_loc_t oloc,
51 H5G_loc_t *obj_loc);
52
53
54 /*************/
55 /* Functions */
56 /*************/
57
58
59
60 /*-------------------------------------------------------------------------
61 * Function: H5Oflush
62 *
63 * Purpose: Flushes all buffers associated with an object to disk.
64 *
65 * Return: Non-negative on success, negative on failure
66 *
67 * Programmer: Mike McGreevy
68 * May 19, 2010
69 *
70 *-------------------------------------------------------------------------
71 */
72 herr_t
H5Oflush(hid_t obj_id)73 H5Oflush(hid_t obj_id)
74 {
75 herr_t ret_value = SUCCEED; /* Return value */
76
77 FUNC_ENTER_API(FAIL)
78 H5TRACE1("e", "i", obj_id);
79
80 /* Set up collective metadata if appropriate */
81 if(H5CX_set_loc(obj_id) < 0)
82 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't set access property list info")
83
84 /* Call internal routine */
85 if(H5O__flush(obj_id) < 0)
86 HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object")
87
88 done:
89 FUNC_LEAVE_API(ret_value)
90 } /* end H5Oflush() */
91
92
93 /*-------------------------------------------------------------------------
94 * Function: H5O_flush_common
95 *
96 * Purpose: Flushes the object's metadata
97 * Invokes the user-defined callback if there is one.
98 *
99 * Return: Non-negative on success, negative on failure
100 *
101 * Programmer: Vailin Choi; Dec 2013
102 *
103 *-------------------------------------------------------------------------
104 */
105 herr_t
H5O_flush_common(H5O_loc_t * oloc,hid_t obj_id)106 H5O_flush_common(H5O_loc_t *oloc, hid_t obj_id)
107 {
108 haddr_t tag = 0;
109 herr_t ret_value = SUCCEED; /* Return value */
110
111 FUNC_ENTER_NOAPI(FAIL)
112
113 /* Retrieve tag for object */
114 if(H5O__oh_tag(oloc, &tag) < 0)
115 HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object metadata")
116
117 /* Flush metadata based on tag value of the object */
118 if(H5F_flush_tagged_metadata(oloc->file, tag) < 0)
119 HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata")
120
121 /* Check to invoke callback */
122 if(H5F_object_flush_cb(oloc->file, obj_id) < 0)
123 HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to do object flush callback")
124
125 done:
126 FUNC_LEAVE_NOAPI(ret_value)
127 } /* end H5O_flush_common() */
128
129
130 /*-------------------------------------------------------------------------
131 * Function: H5O__flush
132 *
133 * Purpose: Internal routine to flush an object
134 *
135 * Return: Success: Non-negative
136 * Failure: Negative
137 *
138 * Programmer: Quincey Koziol
139 * December 29, 2017
140 *
141 *-------------------------------------------------------------------------
142 */
143 static herr_t
H5O__flush(hid_t obj_id)144 H5O__flush(hid_t obj_id)
145 {
146 H5O_loc_t *oloc; /* Object location */
147 void *obj_ptr; /* Pointer to object */
148 const H5O_obj_class_t *obj_class; /* Class of object */
149 herr_t ret_value = SUCCEED; /* Return value */
150
151 FUNC_ENTER_STATIC
152
153 /* Check args */
154 if(NULL == (oloc = H5O_get_loc(obj_id)))
155 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object")
156
157 /* Get the object pointer */
158 if(NULL == (obj_ptr = H5I_object(obj_id)))
159 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier")
160
161 /* Get the object class */
162 if(NULL == (obj_class = H5O__obj_class(oloc)))
163 HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object class")
164
165 /* Flush the object of this class */
166 if(obj_class->flush && obj_class->flush(obj_ptr) < 0)
167 HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object")
168
169 /* Flush the object metadata and invoke flush callback */
170 if(H5O_flush_common(oloc, obj_id) < 0)
171 HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object and object flush callback")
172
173 done:
174 FUNC_LEAVE_NOAPI(ret_value)
175 } /* end H5O__flush() */
176
177
178 /*-------------------------------------------------------------------------
179 * Function: H5O__oh_tag
180 *
181 * Purpose: Get object header's address--tag value for the object
182 *
183 * Return: Success: Non-negative
184 * Failure: Negative
185 *
186 * Programmer: Mike McGreevy
187 * May 19, 2010
188 *
189 *-------------------------------------------------------------------------
190 */
191 static herr_t
H5O__oh_tag(const H5O_loc_t * oloc,haddr_t * tag)192 H5O__oh_tag(const H5O_loc_t *oloc, haddr_t *tag)
193 {
194 H5O_t *oh = NULL; /* Object header */
195 herr_t ret_value = SUCCEED; /* Return value */
196
197 FUNC_ENTER_STATIC
198
199 /* Check args */
200 HDassert(oloc);
201
202 /* Get object header for object */
203 if(NULL == (oh = H5O_protect(oloc, H5AC__READ_ONLY_FLAG, FALSE)))
204 HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object's object header")
205
206 /* Get object header's address (i.e. the tag value for this object) */
207 if(HADDR_UNDEF == (*tag = H5O_OH_GET_ADDR(oh)))
208 HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get address of object header")
209
210 done:
211 /* Unprotect object header on failure */
212 if(oh && H5O_unprotect(oloc, oh, H5AC__NO_FLAGS_SET) < 0)
213 HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
214
215 FUNC_LEAVE_NOAPI(ret_value)
216 } /* end H5O__oh_tag() */
217
218
219 /*-------------------------------------------------------------------------
220 * Function: H5Orefresh
221 *
222 * Purpose: Refreshes all buffers associated with an object.
223 *
224 * Return: Non-negative on success, negative on failure
225 *
226 * Programmer: Mike McGreevy
227 * July 28, 2010
228 *
229 *-------------------------------------------------------------------------
230 */
231 herr_t
H5Orefresh(hid_t oid)232 H5Orefresh(hid_t oid)
233 {
234 H5O_loc_t *oloc; /* object location */
235 herr_t ret_value = SUCCEED; /* return value */
236
237 FUNC_ENTER_API(FAIL)
238 H5TRACE1("e", "i", oid);
239
240 /* Check args */
241 if(NULL == (oloc = H5O_get_loc(oid)))
242 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object")
243
244 /* Set up collective metadata if appropriate */
245 if(H5CX_set_loc(oid) < 0)
246 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't set access property list info")
247
248 /* Call internal routine */
249 if(H5O_refresh_metadata(oid, *oloc) < 0)
250 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
251
252 done:
253 FUNC_LEAVE_API(ret_value)
254 } /* end H5Orefresh() */
255
256
257 /*-------------------------------------------------------------------------
258 * Function: H5O_refresh_metadata
259 *
260 * Purpose: Refreshes all buffers associated with an object.
261 *
262 * Note: This is based on the original H5O_refresh_metadata() but
263 * is split into 2 routines.
264 * This is done so that H5Fstart_swmr_write() can use these
265 * 2 routines to refresh opened objects. This may be
266 * restored back to the original code when H5Fstart_swmr_write()
267 * uses a different approach to handle issues with opened objects.
268 * H5Fstart_swmr_write() no longer calls the 1st routine. (12/24/15)
269 *
270 * Return: Non-negative on success, negative on failure
271 *
272 * Programmer: Mike McGreevy/Vailin Choi
273 * July 28, 2010/Feb 2014
274 *
275 *-------------------------------------------------------------------------
276 */
277 herr_t
H5O_refresh_metadata(hid_t oid,H5O_loc_t oloc)278 H5O_refresh_metadata(hid_t oid, H5O_loc_t oloc)
279 {
280 hbool_t objs_incr = FALSE; /* Whether the object count in the file was incremented */
281 herr_t ret_value = SUCCEED; /* Return value */
282
283 FUNC_ENTER_NOAPI(FAIL)
284
285 /* If the file is opened with write access, no need to perform refresh actions. */
286 if(!(H5F_INTENT(oloc.file) & H5F_ACC_RDWR)) {
287 H5G_loc_t obj_loc;
288 H5O_loc_t obj_oloc;
289 H5G_name_t obj_path;
290
291 /* Create empty object location */
292 obj_loc.oloc = &obj_oloc;
293 obj_loc.path = &obj_path;
294 H5G_loc_reset(&obj_loc);
295
296 /* "Fake" another open object in the file, so that it doesn't get closed
297 * if this object is the only thing holding the file open.
298 */
299 H5F_incr_nopen_objs(oloc.file);
300 objs_incr = TRUE;
301
302 /* Close object & evict its metadata */
303 if((H5O__refresh_metadata_close(oid, oloc, &obj_loc)) < 0)
304 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
305
306 /* Re-open the object, re-fetching its metadata */
307 if((H5O_refresh_metadata_reopen(oid, &obj_loc, FALSE)) < 0)
308 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
309 } /* end if */
310
311 done:
312 if(objs_incr)
313 H5F_decr_nopen_objs(oloc.file);
314
315 FUNC_LEAVE_NOAPI(ret_value);
316 } /* end H5O_refresh_metadata() */
317
318
319 /*-------------------------------------------------------------------------
320 * Function: H5O__refresh_metadata_close
321 *
322 * Purpose: This is the first part of the original routine H5O_refresh_metadata().
323 * (1) Save object location information.
324 * (2) Handle multiple dataset opens
325 * (3) Get object cork status
326 * (4) Close the object
327 * (5) Flush and evict object metadata
328 * (6) Re-cork the object if needed
329 *
330 * Return: Success: Non-negative
331 * Failure: Negative
332 *
333 * Programmer: Mike McGreevy/Vailin Choi
334 * July 28, 2010/Feb 2014
335 *
336 *-------------------------------------------------------------------------
337 */
338 static herr_t
H5O__refresh_metadata_close(hid_t oid,H5O_loc_t oloc,H5G_loc_t * obj_loc)339 H5O__refresh_metadata_close(hid_t oid, H5O_loc_t oloc, H5G_loc_t *obj_loc)
340 {
341 haddr_t tag = 0; /* Tag for object */
342 hbool_t corked = FALSE; /* Whether object's metadata is corked */
343 herr_t ret_value = SUCCEED; /* Return value */
344
345 FUNC_ENTER_STATIC
346
347 /* Make deep local copy of object's location information */
348 if(obj_loc) {
349 H5G_loc_t tmp_loc;
350
351 H5G_loc(oid, &tmp_loc);
352 H5G_loc_copy(obj_loc, &tmp_loc, H5_COPY_DEEP);
353 } /* end if */
354
355 /* Get object's type */
356 if(H5I_get_type(oid) == H5I_DATASET)
357 if(H5D_mult_refresh_close(oid) < 0)
358 HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to prepare refresh for dataset")
359
360 /* Retrieve tag for object */
361 if(H5O__oh_tag(&oloc, &tag) < 0)
362 HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to get object header address")
363
364 /* Get cork status of the object with tag */
365 if(H5AC_cork(oloc.file, tag, H5AC__GET_CORKED, &corked) < 0)
366 HGOTO_ERROR(H5E_ATOM, H5E_SYSTEM, FAIL, "unable to retrieve an object's cork status")
367
368 /* Close the object */
369 if(H5I_dec_ref(oid) < 0)
370 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to close object")
371
372 /* Flush metadata based on tag value of the object */
373 if(H5F_flush_tagged_metadata(oloc.file, tag) < 0)
374 HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata")
375
376 /* Evict the object's tagged metadata */
377 if(H5F_evict_tagged_metadata(oloc.file, tag) < 0)
378 HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to evict metadata")
379
380 /* Re-cork object with tag */
381 if(corked)
382 if(H5AC_cork(oloc.file, tag, H5AC__SET_CORK, &corked) < 0)
383 HGOTO_ERROR(H5E_ATOM, H5E_SYSTEM, FAIL, "unable to cork the object")
384
385 done:
386 FUNC_LEAVE_NOAPI(ret_value);
387 } /* end H5O__refresh_metadata_close() */
388
389
390 /*-------------------------------------------------------------------------
391 * Function: H5O_refresh_metadata_reopen
392 *
393 * Purpose: This is the second part of the original routine H5O_refresh_metadata().
394 * (1) Re-open object with the saved object location information.
395 * (2) Re-register object ID with the re-opened object.
396 *
397 * Return: SUCCEED/FAIL
398 *
399 * Programmer: Mike McGreevy/Vailin Choi
400 * July 28, 2010/Feb 2014
401 *
402 *-------------------------------------------------------------------------
403 */
404 herr_t
H5O_refresh_metadata_reopen(hid_t oid,H5G_loc_t * obj_loc,hbool_t start_swmr)405 H5O_refresh_metadata_reopen(hid_t oid, H5G_loc_t *obj_loc, hbool_t start_swmr)
406 {
407 void *object = NULL; /* Dataset for this operation */
408 H5I_type_t type; /* Type of object for the ID */
409 herr_t ret_value = SUCCEED; /* Return value */
410
411 FUNC_ENTER_NOAPI(FAIL)
412
413 /* Get object's type */
414 type = H5I_get_type(oid);
415
416 switch(type) {
417 case H5I_GROUP:
418 /* Re-open the group */
419 if(NULL == (object = H5G_open(obj_loc)))
420 HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
421 break;
422
423 case H5I_DATATYPE:
424 /* Re-open the named datatype */
425 if(NULL == (object = H5T_open(obj_loc)))
426 HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to open named datatype")
427 break;
428
429 case H5I_DATASET:
430 /* Re-open the dataset */
431 if(NULL == (object = H5D_open(obj_loc, H5P_DATASET_ACCESS_DEFAULT)))
432 HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open dataset")
433 if(!start_swmr) /* No need to handle multiple opens when H5Fstart_swmr_write() */
434 if(H5D_mult_refresh_reopen((H5D_t *)object) < 0)
435 HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to finish refresh for dataset")
436 break;
437
438 case H5I_UNINIT:
439 case H5I_BADID:
440 case H5I_FILE:
441 case H5I_DATASPACE:
442 case H5I_ATTR:
443 case H5I_REFERENCE:
444 case H5I_VFL:
445 case H5I_GENPROP_CLS:
446 case H5I_GENPROP_LST:
447 case H5I_ERROR_CLASS:
448 case H5I_ERROR_MSG:
449 case H5I_ERROR_STACK:
450 case H5I_NTYPES:
451 default:
452 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a valid file object ID (dataset, group, or datatype)")
453 break;
454 } /* end switch */
455
456 /* Re-register ID for the object */
457 if((H5I_register_with_id(type, object, TRUE, oid)) < 0)
458 HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to re-register object atom")
459
460 done:
461 FUNC_LEAVE_NOAPI(ret_value);
462 } /* end H5O_refresh_metadata_reopen() */
463
464