hdf5/src/H5Oflush.c
Quincey Koziol 64a339183f Bring SWMR support in to the main development branch. (Finally!) More tests
and the tool and API wrappers will be coming in over the weekend.
2016-12-02 08:07:04 -08:00

422 lines
15 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
* Copyright by the Board of Trustees of the University of Illinois. *
* All rights reserved. *
* *
* This file is part of HDF5. The full HDF5 copyright notice, including *
* terms governing use, modification, and redistribution, is contained in *
* the files COPYING and Copyright.html. COPYING can be found at the root *
* of the source code distribution tree; Copyright.html can be found at the *
* root level of an installed copy of the electronic HDF5 document set and *
* is linked from the top-level documents page. It can also be found at *
* http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
* access to either file, you may request a copy from help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*-------------------------------------------------------------------------
*
* Created: H5Oflush.c
* Aug 19, 2010
* Mike McGreevy <mamcgree@hdfgroup.org>
*
* Purpose: Object flush/refresh routines.
*
*-------------------------------------------------------------------------
*/
/****************/
/* Module Setup */
/****************/
#include "H5Omodule.h" /* This source code file is part of the H5O module */
/***********/
/* Headers */
/***********/
#include "H5private.h" /* Generic Functions */
#include "H5Dprivate.h" /* Datasets */
#include "H5Eprivate.h" /* Errors */
#include "H5Fprivate.h" /* Files */
#include "H5Gprivate.h" /* Groups */
#include "H5Iprivate.h" /* IDs */
#include "H5Opkg.h" /* Objects */
/********************/
/* Local Prototypes */
/********************/
static herr_t H5O_oh_tag(const H5O_loc_t *oloc, hid_t dxpl_id, haddr_t *tag);
/*************/
/* Functions */
/*************/
/*-------------------------------------------------------------------------
* Function: H5Oflush
*
* Purpose: Flushes all buffers associated with an object to disk.
*
* Return: Non-negative on success, negative on failure
*
* Programmer: Mike McGreevy
* May 19, 2010
*
*-------------------------------------------------------------------------
*/
herr_t
H5Oflush(hid_t obj_id)
{
H5O_loc_t *oloc; /* object location */
void *obj_ptr; /* Pointer to object */
const H5O_obj_class_t *obj_class = NULL; /* Class of object */
herr_t ret_value = SUCCEED; /* return value */
FUNC_ENTER_API(FAIL)
H5TRACE1("e", "i", obj_id);
/* Check args */
if(NULL == (oloc = H5O_get_loc(obj_id)))
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object")
/* Get the object pointer */
if(NULL == (obj_ptr = H5I_object(obj_id)))
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier")
/* Get the object class */
if(NULL == (obj_class = H5O_obj_class(oloc, H5AC_ind_read_dxpl_id)))
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object class")
/* Flush the object of this class */
if(obj_class->flush && obj_class->flush(obj_ptr, H5AC_ind_read_dxpl_id) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object")
/* Flush the object metadata and invoke flush callback */
if(H5O_flush_common(oloc, obj_id, H5AC_ind_read_dxpl_id) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object and object flush callback")
done:
FUNC_LEAVE_API(ret_value)
} /* end H5Oflush() */
/*-------------------------------------------------------------------------
* Function: H5O_flush_common
*
* Purpose: Flushes the object's metadata
* Invokes the user-defined callback if there is one.
*
* Return: Non-negative on success, negative on failure
*
* Programmer: Vailin Choi; Dec 2013
*
*-------------------------------------------------------------------------
*/
herr_t
H5O_flush_common(H5O_loc_t *oloc, hid_t obj_id, hid_t dxpl_id)
{
haddr_t tag = 0;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(FAIL)
/* Retrieve tag for object */
if(H5O_oh_tag(oloc, dxpl_id, &tag) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object metadata")
/* Flush metadata based on tag value of the object */
if(H5F_flush_tagged_metadata(oloc->file, tag, dxpl_id) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata")
/* Check to invoke callback */
if(H5F_object_flush_cb(oloc->file, obj_id) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to do object flush callback")
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_flush_common() */
/*-------------------------------------------------------------------------
* Function: H5O_oh_tag
*
* Purpose: Get object header's address--tag value for the object
*
* Return: Success: Non-negative
* Failure: Negative
*
* Programmer: Mike McGreevy
* May 19, 2010
*
*-------------------------------------------------------------------------
*/
static herr_t
H5O_oh_tag(const H5O_loc_t *oloc, hid_t dxpl_id, haddr_t *tag)
{
H5O_t *oh = NULL; /* Object header */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(FAIL)
/* Check args */
HDassert(oloc);
/* Get object header for object */
if(NULL == (oh = H5O_protect(oloc, dxpl_id, H5AC__READ_ONLY_FLAG, FALSE)))
HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object's object header")
/* Get object header's address (i.e. the tag value for this object) */
if(HADDR_UNDEF == (*tag = H5O_OH_GET_ADDR(oh)))
HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get address of object header")
done:
/* Unprotect object header on failure */
if(oh && H5O_unprotect(oloc, dxpl_id, oh, H5AC__NO_FLAGS_SET) < 0)
HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_oh_tag() */
/*-------------------------------------------------------------------------
* Function: H5Orefresh
*
* Purpose: Refreshes all buffers associated with an object.
*
* Return: Non-negative on success, negative on failure
*
* Programmer: Mike McGreevy
* July 28, 2010
*
*-------------------------------------------------------------------------
*/
herr_t
H5Orefresh(hid_t oid)
{
H5O_loc_t *oloc; /* object location */
herr_t ret_value = SUCCEED; /* return value */
FUNC_ENTER_API(FAIL)
H5TRACE1("e", "i", oid);
/* Check args */
if(NULL == (oloc = H5O_get_loc(oid)))
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an object")
/* Private function */
if(H5O_refresh_metadata(oid, *oloc, H5AC_ind_read_dxpl_id) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
done:
FUNC_LEAVE_API(ret_value)
} /* end H5Orefresh() */
/*-------------------------------------------------------------------------
* Function: H5O_refresh_metadata
*
* Purpose: Refreshes all buffers associated with an object.
*
* Note: This is based on the original H5O_refresh_metadata() but
* is split into 2 routines.
* This is done so that H5Fstart_swmr_write() can use these
* 2 routines to refresh opened objects. This may be
* restored back to the original code when H5Fstart_swmr_write()
* uses a different approach to handle issues with opened objects.
* H5Fstart_swmr_write() no longer calls the 1st routine. (12/24/15)
*
* Return: Non-negative on success, negative on failure
*
* Programmer: Mike McGreevy/Vailin Choi
* July 28, 2010/Feb 2014
*
*-------------------------------------------------------------------------
*/
herr_t
H5O_refresh_metadata(hid_t oid, H5O_loc_t oloc, hid_t dxpl_id)
{
hbool_t objs_incr = FALSE; /* Whether the object count in the file was incremented */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(FAIL)
/* If the file is opened with write access, no need to perform refresh actions. */
if(!(H5F_INTENT(oloc.file) & H5F_ACC_RDWR)) {
H5G_loc_t obj_loc;
H5O_loc_t obj_oloc;
H5G_name_t obj_path;
/* Create empty object location */
obj_loc.oloc = &obj_oloc;
obj_loc.path = &obj_path;
H5G_loc_reset(&obj_loc);
/* "Fake" another open object in the file, so that it doesn't get closed
* if this object is the only thing holding the file open.
*/
H5F_incr_nopen_objs(oloc.file);
objs_incr = TRUE;
/* Close object & evict its metadata */
if((H5O_refresh_metadata_close(oid, oloc, &obj_loc, dxpl_id)) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
/* Re-open the object, re-fetching its metadata */
if((H5O_refresh_metadata_reopen(oid, &obj_loc, dxpl_id, FALSE)) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object")
} /* end if */
done:
if(objs_incr)
H5F_decr_nopen_objs(oloc.file);
FUNC_LEAVE_NOAPI(ret_value);
} /* end H5O_refresh_metadata() */
/*-------------------------------------------------------------------------
* Function: H5O_refresh_metadata_close
*
* Purpose: This is the first part of the original routine H5O_refresh_metadata().
* (1) Save object location information.
* (2) Handle multiple dataset opens
* (3) Get object cork status
* (4) Close the object
* (5) Flush and evict object metadata
* (6) Re-cork the object if needed
*
* Return: Success: Non-negative
* Failure: Negative
*
* Programmer: Mike McGreevy/Vailin Choi
* July 28, 2010/Feb 2014
*
*-------------------------------------------------------------------------
*/
herr_t
H5O_refresh_metadata_close(hid_t oid, H5O_loc_t oloc, H5G_loc_t *obj_loc, hid_t dxpl_id)
{
haddr_t tag = 0; /* Tag for object */
hbool_t corked = FALSE; /* Whether object's metadata is corked */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(FAIL)
/* Make deep local copy of object's location information */
if(obj_loc) {
H5G_loc_t tmp_loc;
H5G_loc(oid, &tmp_loc);
H5G_loc_copy(obj_loc, &tmp_loc, H5_COPY_DEEP);
} /* end if */
/* Get object's type */
if(H5I_get_type(oid) == H5I_DATASET)
if(H5D_mult_refresh_close(oid, dxpl_id) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to prepare refresh for dataset")
/* Retrieve tag for object */
if(H5O_oh_tag(&oloc, dxpl_id, &tag) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTFLUSH, FAIL, "unable to get object header address")
/* Get cork status of the object with tag */
if(H5AC_cork(oloc.file, tag, H5AC__GET_CORKED, &corked) < 0)
HGOTO_ERROR(H5E_ATOM, H5E_SYSTEM, FAIL, "unable to retrieve an object's cork status")
/* Close the object */
if(H5I_dec_ref(oid) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to close object")
/* Flush metadata based on tag value of the object */
if(H5F_flush_tagged_metadata(oloc.file, tag, dxpl_id) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush tagged metadata")
/* Evict the object's tagged metadata */
if(H5F_evict_tagged_metadata(oloc.file, tag, dxpl_id) < 0)
HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to evict metadata")
/* Re-cork object with tag */
if(corked)
if(H5AC_cork(oloc.file, tag, H5AC__SET_CORK, &corked) < 0)
HGOTO_ERROR(H5E_ATOM, H5E_SYSTEM, FAIL, "unable to cork the object")
done:
FUNC_LEAVE_NOAPI(ret_value);
} /* end H5O_refresh_metadata_close() */
/*-------------------------------------------------------------------------
* Function: H5O_refresh_metadata_reopen
*
* Purpose: This is the second part of the original routine H5O_refresh_metadata().
* (1) Re-open object with the saved object location information.
* (2) Re-register object ID with the re-opened object.
*
* Return: SUCCEED/FAIL
*
* Programmer: Mike McGreevy/Vailin Choi
* July 28, 2010/Feb 2014
*
*-------------------------------------------------------------------------
*/
herr_t
H5O_refresh_metadata_reopen(hid_t oid, H5G_loc_t *obj_loc, hid_t dxpl_id, hbool_t start_swmr)
{
void *object = NULL; /* Dataset for this operation */
H5I_type_t type; /* Type of object for the ID */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(FAIL)
/* Get object's type */
type = H5I_get_type(oid);
switch(type) {
case(H5I_GROUP):
/* Re-open the group */
if(NULL == (object = H5G_open(obj_loc, dxpl_id)))
HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
break;
case(H5I_DATATYPE):
/* Re-open the named datatype */
if(NULL == (object = H5T_open(obj_loc, dxpl_id)))
HGOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, "unable to open named datatype")
break;
case(H5I_DATASET):
/* Re-open the dataset */
if(NULL == (object = H5D_open(obj_loc, H5P_DATASET_ACCESS_DEFAULT, dxpl_id)))
HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open dataset")
if(!start_swmr) /* No need to handle multiple opens when H5Fstart_swmr_write() */
if(H5D_mult_refresh_reopen((H5D_t *)object, dxpl_id) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to finish refresh for dataset")
break;
case(H5I_UNINIT):
case(H5I_BADID):
case(H5I_FILE):
case(H5I_DATASPACE):
case(H5I_ATTR):
case(H5I_REFERENCE):
case(H5I_VFL):
case(H5I_GENPROP_CLS):
case(H5I_GENPROP_LST):
case(H5I_ERROR_CLASS):
case(H5I_ERROR_MSG):
case(H5I_ERROR_STACK):
case(H5I_NTYPES):
default:
HGOTO_ERROR(H5E_ARGS, H5E_CANTRELEASE, FAIL, "not a valid file object ID (dataset, group, or datatype)")
break;
} /* end switch */
/* Re-register ID for the object */
if((H5I_register_with_id(type, object, TRUE, oid)) < 0)
HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to re-register object atom")
done:
FUNC_LEAVE_NOAPI(ret_value);
} /* end H5O_refresh_metadata_reopen() */