summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Mainzer <mainzer@hdfgroup.org>2015-12-11 04:53:08 (GMT)
committerJohn Mainzer <mainzer@hdfgroup.org>2015-12-11 04:53:08 (GMT)
commit6671139328e03686e8e76b9401352476b5ccc329 (patch)
tree34b60da1e8002fcfb1d167021ffb067329b76056
parent68037d059e261fe14dc15279402b8c9bd0992faa (diff)
downloadhdf5-6671139328e03686e8e76b9401352476b5ccc329.zip
hdf5-6671139328e03686e8e76b9401352476b5ccc329.tar.gz
hdf5-6671139328e03686e8e76b9401352476b5ccc329.tar.bz2
[svn-r28579] Checkin of fixes to more bugs uncovered by investigation of
SWMR-95 -- specifically: 1) Code in H5C__flush_single_entry() taking down all remaining flush dependencies before an entry is destroyed. Replaced this with code asserting that all flush dependencies have been taken down by the cache client as required by the protocol for managing flush dependencies. This exposed: 2) Both the object header proxy and the object header continuation chunk cache clients were failing to track their flush dependency parents, and thus were relying on the above code in H5C__flush_single_entry() to take down their flush dependencies instead of handling this issue in their notify callbacks. Fixing item 2 for the object header continuation chunks was straight forward, as each object header continuation chunk can have at most one flush dependency parent. However, there is no upper bound on the number of flush dependency parents for an object header proxy (one must be an object header -- any additional flush dependency parents must be object header continuation chunks). This said, in most cases object header proxies have only one flush dependency parent. To handle this, I adapted Neil's code for tracking multiple flush dependency parents in the metadata cache for use in the object header proxy, with the difference that I set the initial array size to 1 (Neil uses 8). To change this, modify H5O_FD_PAR_LIST_BASE in H5Opkg.h Potential issues with this fix: 1) While the fix passes the existing regression tests, I don't believe these test the code for tracking multiple flush dependency parents in the object header proxy adequately. From discussions with Quincey, I gather that the obvious way to do this is to add and delete large numbers of properties to/from the object header, forcing increases and decreases in the number of object header continuation chunks. However, as I am unfamiliar with the layout of the SWMR test code, it seemed inefficient for me to address this issue -- hence I gather that it will be handled elsewhere. 2) My fix tracks both pointers to flush dependency parents and their addresses. As the addresses are used purely for sanity checking, once we are reasonably confident of my fix, the code can be modified to either to remove the address tracking and the associated sanity checks completely, or to maintain the addresses in debug builds only. Note that the address tracking code presumes that object headers and object header continuation chunks cannot change addresses. If this ever changes, the sanity checking code will complain. Tested (debug only) serial and parallel on Mercury, serial on Jam.
-rw-r--r--src/H5C.c43
-rw-r--r--src/H5Oalloc.c19
-rw-r--r--src/H5Ocache.c32
-rw-r--r--src/H5Ochunk.c3
-rw-r--r--src/H5Opkg.h81
-rw-r--r--src/H5Oproxy.c342
6 files changed, 491 insertions, 29 deletions
diff --git a/src/H5C.c b/src/H5C.c
index 64aacd9..448e6fe 100644
--- a/src/H5C.c
+++ b/src/H5C.c
@@ -8423,25 +8423,32 @@ H5C__flush_single_entry(const H5F_t *f, hid_t dxpl_id, H5C_cache_entry_t *entry_
H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, FAIL)
- /* Destroy parent flush dependencies and free flush dependency parent
- * array, if necessary */
+#if 0 /* this is useful debugging code -- leave it in for now. -- JRM */
+ if ( ( entry_ptr->flush_dep_nparents > 0 ) ||
+ ( entry_ptr->flush_dep_nchildren > 0 ) ) {
+
+ int i;
+
+ HDfprintf(stdout,
+ "\n\nattempting to evict entry of type \"%s\" at 0X%llx:\n",
+ entry_ptr->type->name, (long long)(entry_ptr->addr));
+
+ for ( i = 0; i < entry_ptr->flush_dep_nparents; i++ ) {
+
+ HDfprintf(stdout,
+ " with FD parent of type \"%s\" at 0X%llx.\n",
+ entry_ptr->flush_dep_parent[i]->type->name,
+ (long long)(entry_ptr->flush_dep_parent[i]->addr));
+ }
+
+ HDfprintf(stdout, " with %d FD children.\n\n",
+ entry_ptr->flush_dep_nchildren);
+ }
+#endif /* this is useful debugging code -- leave it in for now. -- JRM */
+
+ /* verify that the entry is no longer part of any flush dependencies */
+ HDassert(entry_ptr->flush_dep_nparents == 0);
HDassert(entry_ptr->flush_dep_nchildren == 0);
- if(entry_ptr->flush_dep_parent_nalloc > 0) {
- while(entry_ptr->flush_dep_nparents > 0) {
- /* Since the flush_dep_parent array willbe resized every
- * a flush dependency is destroyed, we do not have to
- * iterate over all indices. Instead, always destroy the
- * last dependency so we can skip the memmove() in
- * H5C_destroy_flush_dependency(). */
- if(H5C_destroy_flush_dependency(entry_ptr->flush_dep_parent[entry_ptr->flush_dep_nparents - 1], entry_ptr) < 0)
- HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Can't remove flush dependency")
- } /* end while */
-
- /* H5C_destroy_flush_dependency should have freed the parent
- * array when it became empty */
- HDassert(!(entry_ptr->flush_dep_parent));
- HDassert(entry_ptr->flush_dep_parent_nalloc == 0);
- } /* end if */
}
else {
HDassert(clear_only || write_entry);
diff --git a/src/H5Oalloc.c b/src/H5Oalloc.c
index 146412f..7263ca6 100644
--- a/src/H5Oalloc.c
+++ b/src/H5Oalloc.c
@@ -1599,14 +1599,33 @@ H5O_move_msgs_forward(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
/* Remove flush dependency on old continuation
* message chunk */
+ HDassert(cont_targ_chk_proxy);
+ HDassert(cont_targ_chk_proxy->fd_parent_addr != HADDR_UNDEF);
+ HDassert(cont_targ_chk_proxy->fd_parent_ptr);
+ HDassert(curr_chk_proxy);
+ HDassert((void *)curr_chk_proxy == cont_targ_chk_proxy->fd_parent_ptr);
+ HDassert(H5F_addr_eq(curr_chk_proxy->cache_info.addr, cont_targ_chk_proxy->fd_parent_addr));
+
if(H5AC_destroy_flush_dependency(curr_chk_proxy, cont_targ_chk_proxy) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+ cont_targ_chk_proxy->fd_parent_addr = HADDR_UNDEF;
+ cont_targ_chk_proxy->fd_parent_ptr = NULL;
+
/* Create flush dependency on new continuation
* message chunk */
if(H5AC_create_flush_dependency(null_chk_mdc_obj, cont_targ_chk_proxy) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ HDassert(null_chk_mdc_obj);
+ HDassert(((H5C_cache_entry_t *)null_chk_mdc_obj)->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(((H5C_cache_entry_t *)null_chk_mdc_obj)->type);
+ HDassert((((H5C_cache_entry_t *)null_chk_mdc_obj)->type->id == H5AC_OHDR_ID) ||
+ (((H5C_cache_entry_t *)null_chk_mdc_obj)->type->id == H5AC_OHDR_CHK_ID));
+
+ cont_targ_chk_proxy->fd_parent_addr = ((H5C_cache_entry_t *)null_chk_mdc_obj)->addr;
+ cont_targ_chk_proxy->fd_parent_ptr = null_chk_mdc_obj;
+
/* Unprotect continuation message target chunk
*/
if(H5O_chunk_unprotect(f, dxpl_id, cont_targ_chk_proxy, FALSE) < 0)
diff --git a/src/H5Ocache.c b/src/H5Ocache.c
index 3ee3367..fb12a06 100644
--- a/src/H5Ocache.c
+++ b/src/H5Ocache.c
@@ -924,6 +924,12 @@ H5O__cache_chk_deserialize(const void *image, size_t len, void *_udata,
if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
+ /* initialize the flush dependency parent fields. If needed, they
+ * will be set in the notify routine.
+ */
+ chk_proxy->fd_parent_addr = HADDR_UNDEF;
+ chk_proxy->fd_parent_ptr = NULL;
+
/* Check if we are still decoding the object header */
/* (as opposed to bringing a piece of it back from the file) */
if(udata->decoding) {
@@ -1097,6 +1103,23 @@ H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing)
if(H5AC_create_flush_dependency(parent, chk_proxy) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+ /* make note of the address and pointer of the flush
+ * dependency parent so we can take the dependency down
+ * on eviction.
+ */
+ HDassert(parent);
+ HDassert(((H5C_cache_entry_t *)parent)->magic ==
+ H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(((H5C_cache_entry_t *)parent)->type);
+ HDassert((((H5C_cache_entry_t *)(parent))->type->id
+ == H5AC_OHDR_ID) ||
+ (((H5C_cache_entry_t *)(parent))->type->id
+ == H5AC_OHDR_CHK_ID));
+
+ chk_proxy->fd_parent_addr = ((H5C_cache_entry_t *)parent)->addr;
+ chk_proxy->fd_parent_ptr = parent;
+
+
/* Add flush dependency on object header proxy, if proxy exists */
if(chk_proxy->oh->proxy_present)
if(H5O_proxy_depend(chk_proxy->f, H5AC_ind_dxpl_id, chk_proxy->oh, chk_proxy) < 0)
@@ -1107,7 +1130,14 @@ H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing)
break;
case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
- /* Nothing to do */
+ HDassert(chk_proxy->fd_parent_addr != HADDR_UNDEF);
+ HDassert(chk_proxy->fd_parent_ptr != NULL);
+ HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent_ptr))->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent_ptr))->type);
+ HDassert((((H5C_cache_entry_t *)(chk_proxy->fd_parent_ptr))->type->id == H5AC_OHDR_ID) || (((H5C_cache_entry_t *)(chk_proxy->fd_parent_ptr))->type->id == H5AC_OHDR_CHK_ID));
+
+ if(H5AC_destroy_flush_dependency(chk_proxy->fd_parent_ptr, chk_proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
break;
default:
diff --git a/src/H5Ochunk.c b/src/H5Ochunk.c
index d2a2060..2ccb2f3 100644
--- a/src/H5Ochunk.c
+++ b/src/H5Ochunk.c
@@ -117,6 +117,9 @@ H5O_chunk_add(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned idx,
chk_proxy->chunkno = idx;
chk_proxy->cont_chunkno = cont_chunkno;
+ chk_proxy->fd_parent_addr = HADDR_UNDEF;
+ chk_proxy->fd_parent_ptr = NULL;
+
/* Increment reference count on object header */
if(H5O_inc_rc(oh) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "can't increment reference count on object header")
diff --git a/src/H5Opkg.h b/src/H5Opkg.h
index 0c6a124..a75817e 100644
--- a/src/H5Opkg.h
+++ b/src/H5Opkg.h
@@ -48,6 +48,17 @@
* and 'size' callback for places to change when updating this. */
#define H5O_VERSION_LATEST H5O_VERSION_2
+/* This is the initial size of the dynamically allocated list of object
+ * header continuation chunk flush dependency parents maintained by the
+ * object header proxy.
+ *
+ * The current value of 1 presumes that the typical number of entries
+ * on this list is almost always either zero or 1. Increase this value
+ * if appropriate.
+ */
+#define H5O_FD_PAR_LIST_BASE 1
+
+
/*
* Align messages on 8-byte boundaries because we would like to copy the
* object header chunks directly into memory and operate on them there, even
@@ -380,6 +391,30 @@ typedef struct H5O_chunk_proxy_t {
H5O_t *oh; /* Object header for this chunk */
unsigned chunkno; /* Chunk number for this chunk */
unsigned cont_chunkno; /* Chunk number for the chunk containing the continuation message that points to this chunk */
+
+ /* Flush depencency parent information (not stored)
+ *
+ * The following fields are used to store the base address and a pointer
+ * to the in core representation of the chunk proxy's flush dependency
+ * parent -- if it exists. If it does not exist, these fields will
+ * contain HADDR_UNDEF and NULL respectively.
+ *
+ * If the file is opened in SWMR write mode, the flush dependency
+ * parent of the chunk proxy will be either its object header
+ * (if cont_chunkno == 0) or the chunk proxy indicated by the
+ * cont_chunkno field (if cont_chunkno > 0).
+ *
+ * Note that the flush dependency parent address is maintained purely
+ * for sanity checking. Once we are reasonably confident of the code,
+ * it can be deleted or be maintained only in debug mode.
+ */
+ haddr_t fd_parent_addr; /* Address of flush dependency parent
+ * if any. This field is initialized
+ * to HADDR_UNDEF.
+ */
+ void * fd_parent_ptr; /* pointer to flush dependency parent
+ * it it exists. NULL otherwise.
+ */
} H5O_chunk_proxy_t;
/* Callback information for loading object header chunk from disk */
@@ -397,6 +432,52 @@ struct H5O_proxy_t {
/* first field in structure */
H5F_t *f; /* Pointer to file for object header/chunk */
H5O_t *oh; /* Object header */
+
+ /* Flush depencency parent information (not stored)
+ *
+ * The following fields are used to store base addresses and pointers
+ * to the in core representations of the object header proxy's flush
+ * dependency parents -- if they exist.
+ *
+ * At present, object header proxies may have two types of parents:
+ *
+ * 1) Exactly one object header.
+ *
+ * 2) Zero or more object header continuation chunks.
+ *
+ * The base address and pointer to the object header flush dependency
+ * parent are stored in the oh_fd_parent_addr and oh_fd_parent_ptr fields.
+ * These fields are set to HADDR_UNDEF and NULL if there is no object
+ * header flush dependency parent. Note that when defined,
+ * oh_fd_parent_ptr should point to the same object as oh.
+ *
+ * The number of object header continuation chunks (H5O_chunk_proxy_t)
+ * that are flush dependency parents of the object header proxy is stored
+ * in chk_fd_parent_count.
+ *
+ * If this field is greater than zero, chk_fd_parent_addrs must point to
+ * a dynamically allocated array of haddr_t of length chk_fd_parent_alloc,
+ * and chk_fd_parent_ptrs must point to a dynamically allocated array of
+ * void * of the same length. These arrays are used to store the base
+ * addresses and pointers to the object header continuation chunk flush
+ * dependency parents of the object header proxy. chk_fd_parent_alloc
+ * must always be greater than or equal to chk_fd_parent_count.
+ *
+ * If chk_fd_parent_count is zero, chk_fd_parent_addrs and
+ * chk_fd_parent_ptrs must be NULL.
+ *
+ * Note that the flush dependency parent addresses are maintined
+ * purely for sanity checking. Once we are confident of the code,
+ * these fields and their supporting code can be either deleted
+ * on maintained only in debug builds.
+ */
+ haddr_t oh_fd_parent_addr;
+ void * oh_fd_parent_ptr;
+
+ unsigned chk_fd_parent_count;
+ unsigned chk_fd_parent_alloc;
+ haddr_t *chk_fd_parent_addrs;
+ void **chk_fd_parent_ptrs;
};
/* Callback information for loading object header proxy */
diff --git a/src/H5Oproxy.c b/src/H5Oproxy.c
index bf1d6c8..811e73e 100644
--- a/src/H5Oproxy.c
+++ b/src/H5Oproxy.c
@@ -71,8 +71,9 @@
/********************/
/* Metadata cache (H5AC) callbacks */
-static herr_t H5O__cache_proxy_get_load_size(const void *image, const void *udata,
- size_t *image_len, size_t *actual_len);
+static herr_t H5O__cache_proxy_get_load_size(const void *image, void *udata,
+ size_t *image_len, size_t *actual_len,
+ hbool_t *compressed_ptr, size_t *compressed_image_len_ptr);
static void *H5O__cache_proxy_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty);
static herr_t H5O__cache_proxy_image_len(const void *thing, size_t *image_len, hbool_t *compressed_ptr,
size_t *compressed_image_len_ptr);
@@ -80,7 +81,9 @@ static herr_t H5O__cache_proxy_serialize(const H5F_t *f, void *image, size_t len
static herr_t H5O__cache_proxy_notify(H5AC_notify_action_t action, void *thing);
static herr_t H5O__cache_proxy_free_icr(void *thing);
+static herr_t H5O_proxy_depend_core(void *parent, H5O_proxy_t *proxy);
static herr_t H5O__cache_proxy_dest(H5O_proxy_t *proxy);
+static herr_t H5O_proxy_undepend_core(void *parent, H5O_proxy_t *proxy);
/*********************/
/* Package Variables */
@@ -116,6 +119,17 @@ const H5AC_class_t H5AC_OHDR_PROXY[1] = {{
/* Declare a free list to manage H5O_proxy_t objects */
H5FL_DEFINE_STATIC(H5O_proxy_t);
+/* Declare a free list to manage flush dependency parent addr arrays.
+ * Note that this array is used purely for sanity checking -- once we
+ * are pretty sure the code is working properly, it can be removed.
+ *
+ * JRM -- 12/10/15
+ */
+H5FL_BLK_DEFINE_STATIC(parent_addr);
+
+/* Declare a free list to manage flush dependency parent ptr arrays */
+H5FL_BLK_DEFINE_STATIC(parent_ptr);
+
/*-------------------------------------------------------------------------
@@ -132,8 +146,10 @@ H5FL_DEFINE_STATIC(H5O_proxy_t);
*-------------------------------------------------------------------------
*/
static herr_t
-H5O__cache_proxy_get_load_size(const void *_image, const void H5_ATTR_UNUSED *_udata,
- size_t *image_len, size_t H5_ATTR_UNUSED *actual_len)
+H5O__cache_proxy_get_load_size(const void *_image, void H5_ATTR_UNUSED *_udata,
+ size_t *image_len, size_t H5_ATTR_UNUSED *actual_len,
+ hbool_t H5_ATTR_UNUSED *compressed_ptr,
+ size_t H5_ATTR_UNUSED *compressed_image_len_ptr)
{
const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
@@ -190,6 +206,14 @@ H5O__cache_proxy_deserialize(const void H5_ATTR_UNUSED *_image, size_t H5_ATTR_U
proxy->f = udata->f;
proxy->oh = udata->oh;
+ proxy->oh_fd_parent_addr = HADDR_UNDEF;
+ proxy->oh_fd_parent_ptr = NULL;
+
+ proxy->chk_fd_parent_count = 0;
+ proxy->chk_fd_parent_alloc = 0;
+ proxy->chk_fd_parent_addrs = NULL;
+ proxy->chk_fd_parent_ptrs = NULL;
+
/* Set return value */
ret_value = proxy;
@@ -294,7 +318,7 @@ H5O__cache_proxy_notify(H5AC_notify_action_t action, void *_thing)
case H5AC_NOTIFY_ACTION_AFTER_INSERT:
case H5AC_NOTIFY_ACTION_AFTER_LOAD:
/* Create flush dependency on object header chunk 0 */
- if(H5AC_create_flush_dependency(proxy->oh, proxy) < 0)
+ if(H5O_proxy_depend_core(proxy->oh, proxy) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
/* Create flush dependencies on all other object header chunks */
@@ -302,7 +326,7 @@ H5O__cache_proxy_notify(H5AC_notify_action_t action, void *_thing)
if(NULL == (chk_proxy = H5O_chunk_protect(proxy->f, H5AC_ind_dxpl_id, proxy->oh, i)))
HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
/* same as before, but looks backward...need to check into that..(proxy, chk_proxy) */
- if(H5AC_create_flush_dependency(chk_proxy, proxy) < 0)
+ if(H5O_proxy_depend_core(chk_proxy, proxy) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
if(H5O_chunk_unprotect(proxy->f, H5AC_ind_dxpl_id, chk_proxy, FALSE) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
@@ -319,9 +343,22 @@ H5O__cache_proxy_notify(H5AC_notify_action_t action, void *_thing)
break;
case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
+ HDassert(proxy->oh_fd_parent_addr != HADDR_UNDEF);
+ HDassert(proxy->oh_fd_parent_ptr != NULL);
+
+ if(H5O_proxy_undepend_core(proxy->oh_fd_parent_ptr, proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency with object header")
+
+ while(proxy->chk_fd_parent_count > 0){
+
+ i = proxy->chk_fd_parent_count - 1;
+
+ if(H5O_proxy_undepend_core(proxy->chk_fd_parent_ptrs[i], proxy)<0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency with object header continuation chunk")
+ }
+
/* Mark proxy as not present on the object header */
proxy->oh->proxy_present = FALSE;
-
break;
default:
@@ -547,8 +584,14 @@ H5O_proxy_depend(H5F_t *f, hid_t dxpl_id, H5O_t *oh, void *parent)
HDassert(f);
HDassert(oh);
+
HDassert(H5F_addr_defined(oh->proxy_addr));
HDassert(parent);
+ HDassert(((H5C_cache_entry_t *)parent)->magic ==
+ H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(((H5C_cache_entry_t *)parent)->type);
+ HDassert((((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_ID) ||
+ (((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_CHK_ID));
udata.f = f;
udata.oh = oh;
@@ -557,7 +600,7 @@ H5O_proxy_depend(H5F_t *f, hid_t dxpl_id, H5O_t *oh, void *parent)
HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header proxy");
/* Add the flush dependency on the parent object */
- if(H5AC_create_flush_dependency(parent, proxy) < 0)
+ if(H5O_proxy_depend_core(parent, proxy) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
/* Unprotect the object header proxy */
@@ -575,6 +618,123 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_proxy_depend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_proxy_depend_core
+ *
+ * Purpose: Creates a flush dependency between the object header proxy
+ * (as child) and the specified object (as parent).
+ *
+ * This function accepts a pointer to the proxy, which it
+ * assumes is somehow locked in the cache. In general, this
+ * means the proxy is protected, however, this is not necessary
+ * when called from the proxy notify routine.
+ *
+ * It also handles the book keeping required to track the flush
+ * dependency parent of the object header proxy.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 12/08/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_proxy_depend_core(void *parent, H5O_proxy_t *proxy)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(parent);
+ HDassert(((H5C_cache_entry_t *)parent)->magic ==
+ H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(((H5C_cache_entry_t *)parent)->type);
+ HDassert((((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_ID) ||
+ (((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_CHK_ID));
+ HDassert(proxy);
+ HDassert(proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(proxy->cache_info.type);
+ HDassert(proxy->cache_info.type->id == H5AC_OHDR_PROXY_ID);
+
+ /* Add the flush dependency on the parent object */
+ if(H5AC_create_flush_dependency(parent, proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
+
+ /* make record of the flush dependency relationship */
+ if(((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_ID) {
+
+ HDassert(proxy->oh_fd_parent_addr == HADDR_UNDEF);
+ HDassert(proxy->oh_fd_parent_ptr == NULL);
+
+ proxy->oh_fd_parent_addr = ((H5C_cache_entry_t *)parent)->addr;
+ proxy->oh_fd_parent_ptr = parent;
+
+ } else {
+
+ HDassert(((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_CHK_ID);
+
+ /* check to see if we need to resize the chunk fd parent arrays */
+ if ( proxy->chk_fd_parent_count >= proxy->chk_fd_parent_alloc ) {
+
+ if ( proxy->chk_fd_parent_alloc == 0 ) {
+
+ /* must allocate arrays */
+ if ( NULL == (proxy->chk_fd_parent_addrs = (haddr_t *)
+ H5FL_BLK_MALLOC(parent_addr,
+ H5O_FD_PAR_LIST_BASE * sizeof(haddr_t))) )
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for flush dependency parent addr list")
+
+ if ( NULL == (proxy->chk_fd_parent_ptrs = (void **)
+ H5FL_BLK_MALLOC(parent_ptr,
+ H5O_FD_PAR_LIST_BASE * sizeof(void *))) )
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for flush dependency parent ptr list")
+
+ proxy->chk_fd_parent_alloc = H5O_FD_PAR_LIST_BASE;
+
+ } else {
+
+ /* resize existing arrays */
+ HDassert(proxy->chk_fd_parent_addrs);
+ HDassert(proxy->chk_fd_parent_ptrs);
+
+ if ( NULL == (proxy->chk_fd_parent_addrs = (haddr_t *)
+ H5FL_BLK_REALLOC(parent_addr,
+ proxy->chk_fd_parent_addrs,
+ 2 * proxy->chk_fd_parent_alloc *
+ sizeof(haddr_t))) )
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory reallocation failed for flush dependency parent addr list")
+
+ if ( NULL == (proxy->chk_fd_parent_ptrs = (void **)
+ H5FL_BLK_REALLOC(parent_ptr,
+ proxy->chk_fd_parent_ptrs,
+ 2 * proxy->chk_fd_parent_alloc *
+ sizeof(void *))) )
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory reallocation failed for flush dependency parent ptr list")
+
+ proxy->chk_fd_parent_alloc *= 2;
+ }
+ }
+
+ HDassert(proxy->chk_fd_parent_count < proxy->chk_fd_parent_alloc);
+
+ (proxy->chk_fd_parent_addrs)[proxy->chk_fd_parent_count] =
+ ((H5C_cache_entry_t *)(parent))->addr;
+
+ (proxy->chk_fd_parent_ptrs)[proxy->chk_fd_parent_count] = parent;
+
+ (proxy->chk_fd_parent_count)++;
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* end H5O_proxy_depend_core() */
+
+
/*-------------------------------------------------------------------------
* Function: H5O_proxy_undepend
@@ -582,6 +742,10 @@ done:
* Purpose: Destroys the flush dependency between the object header
* proxy (as child) and the specified object (as parent).
*
+ * Update: This function also seems to be used to delete
+ * flush dependencies between object header proxy (as child)
+ * and object header chunk continuations (as parent)
+ *
* Return: Non-negative on success/Negative on failure
*
* Programmer: Neil Fortner
@@ -609,8 +773,8 @@ H5O_proxy_undepend(H5F_t *f, hid_t dxpl_id, H5O_t *oh, void *parent)
if(NULL == (proxy = (H5O_proxy_t *)H5AC_protect(f, dxpl_id, H5AC_OHDR_PROXY, oh->proxy_addr, &udata, H5AC__READ_ONLY_FLAG)))
HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to protect object header proxy");
- /* Add the flush dependency on the parent object */
- if(H5AC_destroy_flush_dependency(parent, proxy) < 0)
+ /* destroy the flush dependency on the parent object */
+ if(H5O_proxy_undepend_core(parent, proxy) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
/* Unprotect the object header proxy */
@@ -628,3 +792,161 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_proxy_undepend() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_proxy_undepend_core
+ *
+ * Purpose: Destroys the flush dependency between the object header
+ * proxy (as child) and the specified object (as parent).
+ *
+ * Also update records of the flush dependency parents of
+ * the object header proxy so that they can be taken down
+ * on notification of object header proxy eviction.
+ *
+ * Unlike H5O_proxy_undepend, this function does not
+ * protect and unprotect the object header proxy. Instead,
+ * it takes a pointer to the object header proxy as a
+ * parameter, and presumes that the proxy is protected or
+ * otherwise locked in the metadata cache.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: John Mainzer
+ * 12/8/15
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_proxy_undepend_core(void *parent, H5O_proxy_t *proxy)
+{
+ unsigned i;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(parent);
+
+#ifndef NDEBUG
+ /* do sanity checks */
+ HDassert(parent);
+ HDassert(((H5C_cache_entry_t *)parent)->magic ==
+ H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(((H5C_cache_entry_t *)parent)->type);
+ HDassert((((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_ID) ||
+ (((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_CHK_ID));
+
+ if ( (((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_ID) ) {
+
+ HDassert(proxy->oh_fd_parent_addr != HADDR_UNDEF);
+ HDassert(proxy->oh_fd_parent_ptr != NULL);
+ HDassert(proxy->oh_fd_parent_addr ==
+ (((H5C_cache_entry_t *)(parent))->addr));
+ HDassert(proxy->oh_fd_parent_ptr == parent);
+
+ } else {
+
+ hbool_t found = FALSE;
+
+ HDassert(proxy->chk_fd_parent_alloc > 0);
+ HDassert(proxy->chk_fd_parent_count > 0);
+ HDassert(proxy->chk_fd_parent_addrs);
+ HDassert(proxy->chk_fd_parent_ptrs);
+
+ for( i = 0; i < proxy->chk_fd_parent_count; i++ ) {
+
+ if ( proxy->chk_fd_parent_ptrs[i] == parent ) {
+
+ found = TRUE;
+ break;
+ }
+ }
+
+ HDassert(found);
+ HDassert(proxy->chk_fd_parent_addrs[i] ==
+ (((H5C_cache_entry_t *)(parent))->addr));
+ }
+#endif /* NDEBUG */
+
+ /* destroy the flush dependency on the parent object */
+ if(H5AC_destroy_flush_dependency(parent, proxy) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
+
+ /* delete parent from object header's list of parents */
+ if ( (((H5C_cache_entry_t *)(parent))->type->id == H5AC_OHDR_ID) ) {
+
+ proxy->oh_fd_parent_addr = HADDR_UNDEF;
+ proxy->oh_fd_parent_ptr = NULL;
+
+ } else {
+
+ /* find parent in parent ptrs array */
+ for ( i = 0; i < proxy->chk_fd_parent_count; i++ ) {
+
+ if ( proxy->chk_fd_parent_ptrs[i] == parent ) {
+
+ break;
+ }
+ }
+
+ if ( i == proxy->chk_fd_parent_count )
+
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "Parent entry isn't in chunk fd parent list")
+
+ /* Remove parent entry from chunk fd parent ptr and addr lists */
+ if ( i < proxy->chk_fd_parent_count - 1 ) {
+
+ HDmemmove(&proxy->chk_fd_parent_addrs[i],
+ &proxy->chk_fd_parent_addrs[i+1],
+ (proxy->chk_fd_parent_count - i - 1)
+ * sizeof(proxy->chk_fd_parent_addrs[0]));
+
+ HDmemmove(&proxy->chk_fd_parent_ptrs[i],
+ &proxy->chk_fd_parent_ptrs[i+1],
+ (proxy->chk_fd_parent_count - i - 1)
+ * sizeof(proxy->chk_fd_parent_ptrs[0]));
+ }
+
+ proxy->chk_fd_parent_count--;
+
+ /* shrink or free the fd parent ptr and addr lists as appropriate */
+ if( proxy->chk_fd_parent_count == 0 ) {
+
+ proxy->chk_fd_parent_addrs = (haddr_t *)
+ H5FL_BLK_FREE(parent_addr, proxy->chk_fd_parent_addrs);
+
+ proxy->chk_fd_parent_ptrs = (void **)
+ H5FL_BLK_FREE(parent_ptr, proxy->chk_fd_parent_ptrs);
+
+ proxy->chk_fd_parent_alloc = 0;
+
+ }
+ else if ( ( proxy->chk_fd_parent_count > H5O_FD_PAR_LIST_BASE ) &&
+ ( proxy->chk_fd_parent_count <=
+ (proxy->chk_fd_parent_alloc / 4) ) ) {
+
+ if ( NULL == (proxy->chk_fd_parent_addrs = (haddr_t *)
+ H5FL_BLK_REALLOC(parent_addr, proxy->chk_fd_parent_addrs,
+ (proxy->chk_fd_parent_alloc / 4) *
+ sizeof(haddr_t))) )
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory reallocation failed for chk fd parent addr list")
+
+ if ( NULL == (proxy->chk_fd_parent_ptrs = (void **)
+ H5FL_BLK_REALLOC(parent_ptr, proxy->chk_fd_parent_ptrs,
+ (proxy->chk_fd_parent_alloc / 4) *
+ sizeof(void *))) )
+
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory reallocation failed for chk fd parent ptr list")
+
+ proxy->chk_fd_parent_alloc /= 4;
+
+ } /* end if */
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* end H5O_proxy_undepend_core() */
+