summaryrefslogtreecommitdiffstats
path: root/src/H5AC.c
diff options
context:
space:
mode:
authorRobb Matzke <matzke@llnl.gov>1997-09-10 19:57:56 (GMT)
committerRobb Matzke <matzke@llnl.gov>1997-09-10 19:57:56 (GMT)
commit7ead4a900b4b7980688708ee6794def0793f123c (patch)
tree0c8da24c4ccccd85e105c8da4e6595cc352c720f /src/H5AC.c
parent0a379e1cc1a0cfcc51d3bb1a3e90cbc3310aa820 (diff)
downloadhdf5-7ead4a900b4b7980688708ee6794def0793f123c.zip
hdf5-7ead4a900b4b7980688708ee6794def0793f123c.tar.gz
hdf5-7ead4a900b4b7980688708ee6794def0793f123c.tar.bz2
[svn-r71] Lost my changelog, but basically some new caching functions.
Diffstat (limited to 'src/H5AC.c')
-rw-r--r--src/H5AC.c405
1 files changed, 349 insertions, 56 deletions
diff --git a/src/H5AC.c b/src/H5AC.c
index c3e4008..478923c 100644
--- a/src/H5AC.c
+++ b/src/H5AC.c
@@ -31,19 +31,31 @@
*/
/* #define SORT_BY_ADDR */
-#define PABLO_MASK H5AC_mask
+/*
+ * Debug H5AC_protect() and H5AC_unprotect() by insuring that nothing
+ * accesses protected objects. NDEBUG must not be defined in order for
+ * this to have any effect.
+ */
+/* #define H5AC_DEBUG_PROTECT */
+/*
+ * Private file-scope variables.
+ */
+#define PABLO_MASK H5AC_mask
static int interface_initialize_g = FALSE; /*initialized?*/
#ifdef SORT_BY_ADDR
-static H5AC_cache_t *current_cache_g = NULL; /*for sorting */
+static H5AC_t *current_cache_g = NULL; /*for sorting */
#endif
/*-------------------------------------------------------------------------
* Function: H5AC_new
*
- * Purpose: Initialize the cache just after a file is opened.
+ * Purpose: Initialize the cache just after a file is opened. The
+ * SIZE_HINT is the number of cache slots desired. If you
+ * pass an invalid value then H5AC_NSLOTS is used. You can
+ * turn off caching by using 1 for the SIZE_HINT value.
*
* Return: Success: SUCCEED
*
@@ -58,14 +70,17 @@ static H5AC_cache_t *current_cache_g = NULL; /*for sorting */
*-------------------------------------------------------------------------
*/
herr_t
-H5AC_new (hdf5_file_t *f)
+H5AC_new (hdf5_file_t *f, intn size_hint)
{
FUNC_ENTER (H5AC_new, NULL, FAIL);
assert (f);
assert (NULL==f->cache);
+ if (size_hint<1) size_hint = H5AC_NSLOTS;
- f->cache = H5MM_xcalloc (H5AC_NSLOTS, sizeof (H5AC_cache_t));
+ f->cache = H5MM_xcalloc (1, sizeof (H5AC_t));
+ f->cache->nslots = size_hint;
+ f->cache->slot = H5MM_xcalloc (f->cache->nslots, sizeof (H5AC_slot_t));
FUNC_LEAVE (SUCCEED);
}
@@ -75,6 +90,8 @@ H5AC_new (hdf5_file_t *f)
* Function: H5AC_dest
*
* Purpose: Flushes all data to disk and destroys the cache.
+ * This function fails if any object are protected since the
+ * resulting file might not be consistent.
*
* Return: Success: SUCCEED
*
@@ -100,6 +117,19 @@ H5AC_dest (hdf5_file_t *f)
HRETURN_ERROR (H5E_CACHE, H5E_CANTFLUSH, FAIL);
}
+#if defined(H5AC_DEBUG_PROTECT) && !defined(NDEBUG)
+ {
+ intn i;
+ for (i=0; i<f->cache->nslots; i++) {
+ f->cache->slot[i].prot = H5MM_xfree (f->cache->slot[i].prot);
+ f->cache->slot[i].aprots = 0;
+ f->cache->slot[i].nprots = 0;
+ }
+ }
+#endif
+
+ f->cache->slot = H5MM_xfree (f->cache->slot);
+ f->cache->nslots = 0;
f->cache = H5MM_xfree (f->cache);
FUNC_LEAVE (SUCCEED);
}
@@ -112,6 +142,14 @@ H5AC_dest (hdf5_file_t *f)
* is located in the file, return a pointer to the object.
* The optional UDATA structure is passed down to the function
* that is responsible for loading the object into memory.
+ * The pointer is guaranteed to be valid until the next call
+ * to an H5AC function (if you want a pointer which is valid
+ * indefinately then see H5AC_protect()).
+ *
+ * If H5AC_DEBUG_PROTECT is defined then this function also
+ * checks that the requested object is not currently
+ * protected since it is illegal to modify a protected object
+ * except through the pointer returned by H5AC_protect().
*
* Return: Success: Pointer to the object. The pointer is
* valid until some other cache function
@@ -137,10 +175,11 @@ void *
H5AC_find_f (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
const void *udata)
{
- unsigned idx = H5AC_HASH(addr);
+ unsigned idx;
herr_t status;
void *thing = NULL;
herr_t (*flush)(hdf5_file_t*,hbool_t,haddr_t,void*)=NULL;
+ H5AC_slot_t *slot = NULL;
FUNC_ENTER (H5AC_find, NULL, NULL);
@@ -149,25 +188,36 @@ H5AC_find_f (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
assert (type);
assert (type->load);
assert (type->flush);
-
+ idx = H5AC_HASH (f, addr);
+ slot = f->cache->slot + idx;
+
/*
* Return right away if the item is in the cache.
*/
- if (f->cache[idx].type==type && f->cache[idx].addr==addr) {
- HRETURN (f->cache[idx].thing);
+ if (slot->type==type && slot->addr==addr) {
+ HRETURN (slot->thing);
}
/*
* Fail if the item in the cache is at the correct address but is
* of the wrong type.
*/
- if (f->cache[idx].type && f->cache[idx].addr==addr &&
- f->cache[idx].type!=type) {
+ if (slot->type && slot->type!=type && slot->addr==addr) {
HRETURN_ERROR (H5E_CACHE, H5E_BADTYPE, NULL);
}
-#ifdef DO_NOT_CACHE
- H5AC_flush (f, NULL, 0, TRUE);
+#if defined(H5AC_DEBUG_PROTECT) && !defined(NDEBUG)
+ /*
+ * Check that the requested thing isn't protected, for protected things
+ * can only be modified through the pointer already handed out by the
+ * H5AC_protect() function.
+ */
+ {
+ intn i;
+ for (i=0; i<slot->nprots; i++) {
+ assert (addr!=slot->prot[i].addr);
+ }
+ }
#endif
/*
@@ -181,9 +231,9 @@ H5AC_find_f (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
/*
* Free the previous cache entry if there is one.
*/
- if (f->cache[idx].type) {
- flush = f->cache[idx].type->flush;
- status = (flush)(f, TRUE, f->cache[idx].addr, f->cache[idx].thing);
+ if (slot->type) {
+ flush = slot->type->flush;
+ status = (flush)(f, TRUE, slot->addr, slot->thing);
if (status<0) {
/*
* The old thing could not be removed from the stack.
@@ -199,9 +249,9 @@ H5AC_find_f (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
/*
* Make the cache point to the new thing.
*/
- f->cache[idx].type = type;
- f->cache[idx].addr = addr;
- f->cache[idx].thing = thing;
+ slot->type = type;
+ slot->addr = addr;
+ slot->thing = thing;
FUNC_LEAVE (thing);
}
@@ -234,11 +284,11 @@ H5AC_compare (const void *_a, const void *_b)
assert (current_cache_g);
- if (NULL==current_cache_g[a].type) return 1;
- if (NULL==current_cache_g[b].type) return -1;
+ if (NULL==current_cache_g.slot[a].type) return 1;
+ if (NULL==current_cache_g.slot[b].type) return -1;
- if (current_cache_g[a].addr < current_cache_g[b].addr) return -1;
- if (current_cache_g[a].addr > current_cache_g[b].addr) return 1;
+ if (current_cache_g.slot[a].addr < current_cache_g.slot[b].addr) return -1;
+ if (current_cache_g.slot[a].addr > current_cache_g.slot[b].addr) return 1;
return 0;
}
#endif
@@ -252,6 +302,10 @@ H5AC_compare (const void *_a, const void *_b)
* all types of entries are flushed. If the ADDR is zero then
* all entries of the specified type are flushed.
*
+ * If there are protected objects they will not be flushed.
+ * However, an attempt will be made to flush all non-protected
+ * items before this function returns failure.
+ *
* Return: Success: SUCCEED
*
* Failure: FAIL
@@ -268,16 +322,17 @@ herr_t
H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
hbool_t destroy)
{
- uintn i = H5AC_HASH(addr);
+ uintn i;
herr_t status;
herr_t (*flush)(hdf5_file_t*,hbool_t,haddr_t,void*)=NULL;
- H5AC_cache_t *slot;
+ H5AC_slot_t *slot;
intn *map=NULL;
FUNC_ENTER (H5AC_flush, NULL, FAIL);
assert (f);
assert (f->cache);
+ i = H5AC_HASH (f, addr);
if (!type || 0==addr) {
@@ -286,23 +341,23 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
* Sort the cache entries by address since flushing them in
* ascending order by address may be much more efficient.
*/
- map = H5MM_xmalloc (H5AC_NSLOTS * sizeof(intn));
- for (i=0; i<H5AC_NSLOTS; i++) map[i] = i;
+ map = H5MM_xmalloc (f->cache->nslots * sizeof(intn));
+ for (i=0; i<f->cache->nslots; i++) map[i] = i;
assert (NULL==current_cache_g);
current_cache_g = f->cache;
- HDqsort (map, H5AC_NSLOTS, sizeof(intn), H5AC_compare);
+ HDqsort (map, f->cache->nslots, sizeof(intn), H5AC_compare);
current_cache_g = NULL;
#endif
/*
* Look at all cache entries.
*/
- for (i=0; i<H5AC_NSLOTS; i++) {
+ for (i=0; i<f->cache->nslots; i++) {
#ifdef SORT_BY_ADDR
- slot = f->cache + map[i];
+ slot = f->cache->slot + map[i];
if (NULL==slot->type) break; /*the rest are empty*/
#else
- slot = f->cache + i;
+ slot = f->cache->slot + i;
if (NULL==slot->type) continue;
#endif
if ((!type || type==slot->type) &&
@@ -318,19 +373,28 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
}
map = H5MM_xfree (map);
- } else if (f->cache[i].type==type && f->cache[i].addr==addr) {
+ } else if (f->cache->slot[i].type==type && f->cache->slot[i].addr==addr) {
/*
* Flush just this entry.
*/
- flush = f->cache[i].type->flush;
- status = (flush) (f, destroy, f->cache[i].addr, f->cache[i].thing);
+ flush = f->cache->slot[i].type->flush;
+ status = (flush) (f, destroy, f->cache->slot[i].addr,
+ f->cache->slot[i].thing);
if (status<0) {
HRETURN_ERROR (H5E_CACHE, H5E_CANTFLUSH, FAIL);
}
- if (destroy) f->cache[i].type = NULL;
+ if (destroy) f->cache->slot[i].type = NULL;
}
+ /*
+ * If there are protected objects then fail. However, everything
+ * else should have been flushed.
+ */
+ if (f->cache->nprots>0) {
+ HRETURN_ERROR (H5E_CACHE, H5E_PROTECT, FAIL);
+ }
+
FUNC_LEAVE (SUCCEED);
}
@@ -342,6 +406,9 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
* exist on disk yet, but it must have an address and disk
* space reserved.
*
+ * If H5AC_DEBUG_PROTECT is defined then this function checks
+ * that the object being inserted isn't a protected object.
+ *
* Return: Success: SUCCEED
*
* Failure: FAIL
@@ -358,8 +425,9 @@ herr_t
H5AC_set (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, void *thing)
{
herr_t status;
- uintn idx = H5AC_HASH (addr);
+ uintn idx;
herr_t (*flush)(hdf5_file_t*,hbool_t,haddr_t,void*)=NULL;
+ H5AC_slot_t *slot = NULL;
FUNC_ENTER (H5AC_set, NULL, FAIL);
@@ -369,18 +437,29 @@ H5AC_set (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, void *thing)
assert (type->flush);
assert (addr>=0);
assert (thing);
-
- if (f->cache[idx].type) {
- flush = f->cache[idx].type->flush;
- status = (flush)(f, TRUE, f->cache[idx].addr, f->cache[idx].thing);
+ idx = H5AC_HASH (f, addr);
+ slot = f->cache->slot + idx;
+
+#if defined(H5AC_DEBUG_PROTECT) && !defined(NDEBUG)
+ {
+ intn i;
+ for (i=0; i<slot->nprots; i++) {
+ assert (addr!=slot->prot[i].addr);
+ }
+ }
+#endif
+
+ if (slot->type) {
+ flush = slot->type->flush;
+ status = (flush)(f, TRUE, slot->addr, slot->thing);
if (status<0) {
HRETURN_ERROR (H5E_CACHE, H5E_CANTFLUSH, FAIL);
}
}
- f->cache[idx].type = type;
- f->cache[idx].addr = addr;
- f->cache[idx].thing = thing;
+ slot->type = type;
+ slot->addr = addr;
+ slot->thing = thing;
FUNC_LEAVE (SUCCEED);
}
@@ -392,6 +471,10 @@ H5AC_set (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, void *thing)
* Purpose: Use this function to notify the cache that an object's
* file address changed.
*
+ * If H5AC_DEBUG_PROTECT is defined then this function checks
+ * that the old and new addresses don't correspond to the
+ * address of a protected object.
+ *
* Return: Success: SUCCEED
*
* Failure: FAIL
@@ -408,8 +491,7 @@ herr_t
H5AC_rename (hdf5_file_t *f, const H5AC_class_t *type,
haddr_t old_addr, haddr_t new_addr)
{
- uintn old_idx = H5AC_HASH (old_addr);
- uintn new_idx = H5AC_HASH (new_addr);
+ uintn old_idx, new_idx;
herr_t (*flush)(hdf5_file_t*, hbool_t, haddr_t, void*);
herr_t status;
@@ -420,23 +502,42 @@ H5AC_rename (hdf5_file_t *f, const H5AC_class_t *type,
assert (type);
assert (old_addr>=0);
assert (new_addr>=0);
+ old_idx = H5AC_HASH (f, old_addr);
+ new_idx = H5AC_HASH (f, new_addr);
- if (f->cache[old_idx].type!=type || f->cache[old_idx].addr!=old_addr) {
+#if defined(H5AC_DEBUG_PROTECT) && !defined(NDEBUG)
+ {
+ int i;
+
+ for (i=0; i<f->cache->slot[old_idx].nprots; i++) {
+ assert (old_addr!=f->cache->slot[old_idx].prot[i].addr);
+ }
+ for (i=0; i<f->cache->slot[new_idx].nprots; i++) {
+ assert (new_addr!=f->cache->slot[new_idx].prot[i].addr);
+ }
+ }
+#endif
+
+ /*
+ * We don't need to do anything if the object isn't cached or if the
+ * new hash value is the same as the old one.
+ */
+ if (f->cache->slot[old_idx].type!=type ||
+ f->cache->slot[old_idx].addr!=old_addr) {
HRETURN (SUCCEED);
}
-
if (old_idx==new_idx) {
- f->cache[old_idx].addr = new_addr;
+ f->cache->slot[old_idx].addr = new_addr;
HRETURN (SUCCEED);
}
/*
* Free the item from the destination cache line.
*/
- if (f->cache[new_idx].type) {
- flush = f->cache[new_idx].type->flush;
- status = (flush)(f, TRUE, f->cache[new_idx].addr,
- f->cache[new_idx].thing);
+ if (f->cache->slot[new_idx].type) {
+ flush = f->cache->slot[new_idx].type->flush;
+ status = (flush)(f, TRUE, f->cache->slot[new_idx].addr,
+ f->cache->slot[new_idx].thing);
if (status<0) {
HRETURN_ERROR (H5E_CACHE, H5E_CANTFLUSH, FAIL);
}
@@ -445,11 +546,203 @@ H5AC_rename (hdf5_file_t *f, const H5AC_class_t *type,
/*
* Move the source to the destination (it might not be cached)
*/
- f->cache[new_idx].type = f->cache[old_idx].type;
- f->cache[new_idx].addr = new_addr;
- f->cache[new_idx].thing = f->cache[old_idx].thing;
- f->cache[old_idx].type = NULL;
+ f->cache->slot[new_idx].type = f->cache->slot[old_idx].type;
+ f->cache->slot[new_idx].addr = new_addr;
+ f->cache->slot[new_idx].thing = f->cache->slot[old_idx].thing;
+ f->cache->slot[old_idx].type = NULL;
FUNC_LEAVE (SUCCEED);
}
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_protect
+ *
+ * Purpose: Similar to H5AC_find() except the object is removed from
+ * the cache and given to the caller, preventing other parts
+ * of the program from modifying the protected object or
+ * preempting it from the cache.
+ *
+ * The caller must call H5AC_unprotect() when finished with
+ * the pointer.
+ *
+ * If H5AC_DEBUG_PROTECT is defined then we check that the
+ * requested object isn't already protected.
+ *
+ * Return: Success: Ptr to the object.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Sep 2 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5AC_protect (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
+ const void *udata)
+{
+ int idx;
+ void *thing = NULL;
+ H5AC_slot_t *slot = NULL;
+
+ FUNC_ENTER (H5AC_protect, NULL, NULL);
+
+ /* check args */
+ assert (f);
+ assert (f->cache);
+ assert (type);
+ assert (type->load);
+ assert (type->flush);
+ idx = H5AC_HASH (f, addr);
+ slot = f->cache->slot+idx;
+
+ if (slot->type==type && slot->addr==addr) {
+ /*
+ * The object is already cached; simply remove it from the cache.
+ */
+ thing = slot->thing;
+ slot->type = NULL;
+ slot->addr = 0;
+ slot->thing = NULL;
+
+ } else if (slot->type && slot->addr==addr) {
+ /*
+ * Right address but wrong object type.
+ */
+ HRETURN_ERROR (H5E_CACHE, H5E_BADTYPE, NULL);
+
+ } else {
+#if defined(H5AC_DEBUG_PROTECT) && !defined(NDEBUG)
+ /*
+ * Check that the requested thing isn't protected, for protected things
+ * can only be modified through the pointer already handed out by the
+ * H5AC_protect() function.
+ */
+ intn i;
+ for (i=0; i<slot->nprots; i++) {
+ assert (addr!=slot->prot[i].addr);
+ }
+#endif
+
+ /*
+ * Load a new thing. If it can't be loaded, then return an error
+ * without preempting anything.
+ */
+ if (NULL==(thing=(type->load)(f, addr, udata))) {
+ HRETURN_ERROR (H5E_CACHE, H5E_CANTLOAD, NULL);
+ }
+ }
+
+#if defined(H5AC_DEBUG_PROTECT) && !defined(NDEBUG)
+ /*
+ * Add the protected object to the protect debugging fields of the
+ * cache.
+ */
+ if (slot->nprots>=slot->aprots) {
+ slot->aprots += 10;
+ slot->prot = H5MM_xrealloc (slot->prot,
+ slot->aprots * sizeof(H5AC_prot_t));
+ }
+ slot->prot[slot->nprots].type = type;
+ slot->prot[slot->nprots].addr = addr;
+ slot->prot[slot->nprots].thing = thing;
+ slot->nprots += 1;
+#endif
+
+ f->cache->nprots += 1;
+ FUNC_LEAVE (thing);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5AC_unprotect
+ *
+ * Purpose: This function should be called to undo the effect of
+ * H5AC_protect(). The TYPE and ADDR arguments should be the
+ * same as the corresponding call to H5AC_protect() and the
+ * THING argument should be the value returned by H5AC_protect().
+ *
+ * If H5AC_DEBUG_PROTECT is defined then this function fails
+ * if the TYPE and ADDR arguments are not what was used when the
+ * object was protected or if the object was never protected.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * robb@maya.nuance.com
+ * Sep 2 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5AC_unprotect (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr,
+ void *thing)
+{
+ herr_t status;
+ uintn idx;
+ herr_t (*flush)(hdf5_file_t*,hbool_t,haddr_t,void*)=NULL;
+ H5AC_slot_t *slot = NULL;
+
+ FUNC_ENTER (H5AC_unprotect, NULL, FAIL);
+
+ /* check args */
+ assert (f);
+ assert (f->cache);
+ assert (type);
+ assert (type->flush);
+ assert (addr>=0);
+ assert (thing);
+ idx = H5AC_HASH (f, addr);
+ slot = f->cache->slot + idx;
+
+ /*
+ * Flush any object already in the cache at that location. It had
+ * better not be another copy of the protected object.
+ */
+ if (slot->type) {
+ assert (slot->addr!=addr);
+ flush = slot->type->flush;
+ status = (flush)(f, TRUE, slot->addr, slot->thing);
+ if (status<0) {
+ HRETURN_ERROR (H5E_CACHE, H5E_CANTFLUSH, FAIL);
+ }
+ }
+
+#if defined(H5AC_DEBUG_PROTECT) && !defined(NDEBUG)
+ /*
+ * Remove the object's protect data to indicate that it is no longer
+ * protected.
+ */
+ {
+ int found, i;
+ for (i=0,found=FALSE; i<slot->nprots && !found; i++) {
+ if (addr==slot->prot[i].addr) {
+ assert (slot->prot[i].type==type);
+ HDmemmove (slot->prot+i, slot->prot+i+1,
+ ((slot->nprots-i)-1) * sizeof(H5AC_prot_t));
+ slot->nprots -= 1;
+ found = TRUE;
+ }
+ }
+ assert (found);
+ }
+#endif
+
+ /*
+ * Insert the object back into the cache; it is no longer protected.
+ */
+ slot->type = type;
+ slot->addr = addr;
+ slot->thing = thing;
+ f->cache->nprots -= 1;
+
+ FUNC_LEAVE (SUCCEED);
+}