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