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() */ |