summaryrefslogtreecommitdiffstats
path: root/src/H5Gshad.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Gshad.c')
-rw-r--r--src/H5Gshad.c387
1 files changed, 323 insertions, 64 deletions
diff --git a/src/H5Gshad.c b/src/H5Gshad.c
index 6dc997f..315abed 100644
--- a/src/H5Gshad.c
+++ b/src/H5Gshad.c
@@ -15,13 +15,11 @@
#include <H5Oprivate.h> /*object header messages */
#define PABLO_MASK H5G_shadow_mask
+#undef DEBUG_SHADOWS
/* Is the interface initialized? */
static hbool_t interface_initialize_g = FALSE;
-/* Shadow hash table */
-#define H5G_NSHADOWS 10331
-
typedef struct H5G_hash_t {
haddr_t dir_addr;
H5G_shadow_t *head;
@@ -29,8 +27,92 @@ typedef struct H5G_hash_t {
struct H5G_hash_t *prev;
} H5G_hash_t;
-static H5G_hash_t *H5G_shadow_g[H5G_NSHADOWS];
-
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_check
+ *
+ * Purpose: Checks the shadow data structures for validity. This is a
+ * debugging function only--it aborts on failure!
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Sunday, September 21, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifdef DEBUG_SHADOWS
+void
+H5G_shadow_check (hdf5_file_t *f)
+{
+ H5G_hash_t *hash=NULL;
+ H5G_shadow_t *shadow=NULL, *prev_shadow=NULL;
+ uintn idx;
+ hbool_t shadow_error=FALSE;
+ uintn nerrors=0;
+ static int ncalls=0;
+
+ ncalls++;
+
+ for (idx=0; idx<f->nshadows; idx++) {
+ for (hash=f->shadow[idx]; hash; hash=hash->next) {
+ for (shadow=hash->head,prev_shadow=NULL;
+ shadow;
+ shadow=shadow->next) {
+ shadow_error = FALSE;
+
+ /* Each shadow has a name and the names are in order */
+ if (!shadow->name) {
+ fprintf (stderr, "name=NULL, ");
+ shadow_error = TRUE;
+ }
+ if (prev_shadow && strcmp (prev_shadow->name, shadow->name)>=0) {
+ fprintf (stderr, "names not sorted, ");
+ shadow_error = TRUE;
+ }
+
+ /* Valid directory addresses */
+ if (shadow->dir_addr<0 || (shadow->dir_addr==0 && idx!=0)) {
+ fprintf (stderr, "dir_addr=%lu, ",
+ (unsigned long)(shadow->dir_addr));
+ shadow_error = TRUE;
+ } else if (shadow->dir_addr!=hash->dir_addr) {
+ fprintf (stderr, "dir_addr=%lu (not %lu), ",
+ (unsigned long)(shadow->dir_addr),
+ (unsigned long)(hash->dir_addr));
+ }
+
+ /* Linked to symbol table entry */
+ if (shadow->main && shadow!=shadow->main->shadow) {
+ fprintf (stderr, "entry linkage problem, ");
+ shadow_error = TRUE;
+ }
+
+ /* Shadow linked list is consistent */
+ if (shadow->prev && prev_shadow!=shadow->prev) {
+ fprintf (stderr, "shadow linked list problem, ");
+ shadow_error = TRUE;
+ }
+ prev_shadow = shadow;
+
+ /* If an error occurred then print other info */
+ if (shadow_error) {
+ fprintf (stderr, "idx=%u, shadow=0x%08lx, dir_addr=%lu\n",
+ idx, (unsigned long)shadow,
+ (unsigned long)(shadow->dir_addr));
+ nerrors++;
+ }
+ }
+ }
+ }
+ if (nerrors) {
+ fprintf (stderr, "Error in H5G_shadow_check, call %d\n", ncalls);
+ abort ();
+ }
+}
+#endif
/*-------------------------------------------------------------------------
@@ -171,14 +253,14 @@ H5G_shadow_sync (H5G_entry_t *ent)
*-------------------------------------------------------------------------
*/
H5G_shadow_t *
-H5G_shadow_list (haddr_t dir_addr)
+H5G_shadow_list (hdf5_file_t *f, haddr_t dir_addr)
{
- uintn idx = dir_addr % H5G_NSHADOWS;
+ uintn idx = dir_addr % f->nshadows;
H5G_hash_t *bucket = NULL;
FUNC_ENTER (H5G_shadows, NULL, NULL);
- for (bucket=H5G_shadow_g[idx]; bucket; bucket=bucket->next) {
+ for (bucket=f->shadow[idx]; bucket; bucket=bucket->next) {
if (bucket->dir_addr==dir_addr) {
HRETURN (bucket->head);
}
@@ -223,7 +305,11 @@ H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_ac_ud1_t *ac_udata)
assert (sym); /* The symbol table node */
assert (ac_udata); /* The symbol table header info */
- if ((shadow=H5G_shadow_list (ac_udata->dir_addr))) {
+#ifdef DEBUG_SHADOWS
+ H5G_shadow_check (f);
+#endif
+
+ if ((shadow=H5G_shadow_list (f, ac_udata->dir_addr))) {
heap_addr = ac_udata->heap_addr;
while (i<sym->nsyms && shadow) {
@@ -240,6 +326,8 @@ H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_ac_ud1_t *ac_udata)
if (i<sym->nsyms && s && shadow && !strcmp (s, shadow->name)) {
shadow->main = sym->entry + i;
sym->entry[i].shadow = shadow;
+ i++;
+ shadow = shadow->next;
}
}
}
@@ -247,7 +335,6 @@ H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_ac_ud1_t *ac_udata)
FUNC_LEAVE (SUCCEED);
}
-
/*-------------------------------------------------------------------------
* Function: H5G_shadow_open
@@ -257,6 +344,8 @@ H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_ac_ud1_t *ac_udata)
* object, open the object (again) and return a handle
* to it.
*
+ * DIR can be the null pointer if `ent' is the root entry.
+ *
* Return: Success: Handle to open object
*
* Failure: NULL
@@ -275,89 +364,109 @@ H5G_shadow_open (hdf5_file_t *f, H5G_entry_t *dir, H5G_entry_t *ent)
H5O_stab_t stab;
const char *s = NULL;
H5G_hash_t *hash = NULL;
- H5G_shadow_t *hash_ent = NULL;
+ H5G_shadow_t *hash_ent = NULL, *prev_ent = NULL;
uintn idx;
H5O_name_t name_mesg = {NULL};
H5G_entry_t *ret_value = NULL;
+ haddr_t dir_addr;
FUNC_ENTER (H5G_shadow_open, NULL, NULL);
/* check args */
assert (f);
- assert (dir);
+ assert (ent==f->root_sym || dir);
assert (ent);
+ dir_addr = dir ? dir->header : 0;
- if (ent->shadow) {
+ if ((shadow = ent->shadow)) {
/*
* Object is already open. Open it again.
*/
- ent->shadow->nrefs += 1;
- HRETURN (ent);
-
- } else {
- shadow = H5MM_xcalloc (1, sizeof(H5G_shadow_t));
-
- if (ent==f->root_sym && dir->header<=0) {
- /*
- * We're opening the root entry.
- */
- if (H5O_read (f, NO_ADDR, ent, H5O_NAME, 0, &name_mesg)) {
- shadow->name = H5MM_xstrdup (name_mesg.s);
- H5O_reset (H5O_NAME, &name_mesg);
- } else {
- shadow->name = H5MM_xstrdup ("Root Object");
- }
+ shadow->nrefs += 1;
+ HRETURN (&(shadow->entry));
+ }
- } else {
- /*
- * Some entry other than the root.
- */
- if (NULL==H5O_read (f, NO_ADDR, dir, H5O_STAB, 0, &stab)) {
- HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, NULL);
- }
- if (NULL==(s=H5H_peek (f, stab.heap_addr, ent->name_off))) {
- HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, NULL);
- }
- shadow->name = H5MM_xstrdup (s);
- }
-
+
+ shadow = H5MM_xcalloc (1, sizeof(H5G_shadow_t));
+ if (ent==f->root_sym && 0==dir_addr) {
/*
- * Build the new shadow.
+ * We're opening the root entry.
*/
- ent->shadow = shadow;
- shadow->main = ent;
- shadow->nrefs = 1;
- shadow->entry = *ent;
- shadow->entry.dirty = FALSE;
- shadow->dir_addr = dir->header;
-
+ if (H5O_read (f, NO_ADDR, ent, H5O_NAME, 0, &name_mesg)) {
+ shadow->name = H5MM_xstrdup (name_mesg.s);
+ H5O_reset (H5O_NAME, &name_mesg);
+ } else {
+ shadow->name = H5MM_xstrdup ("Root Object");
+ }
+
+ } else {
/*
- * Link it into the shadow heap
+ * Some entry other than the root.
*/
- idx = dir->header % H5G_NSHADOWS;
- for (hash=H5G_shadow_g[idx]; hash; hash=hash->next) {
- if (hash->dir_addr==dir->header) break;
+ if (NULL==H5O_read (f, NO_ADDR, dir, H5O_STAB, 0, &stab)) {
+ HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, NULL);
}
- if (!hash) {
- hash = H5MM_xcalloc (1, sizeof(H5G_hash_t));
- hash->dir_addr = dir->header;
- hash->next = H5G_shadow_g[idx];
- H5G_shadow_g[idx] = hash;
+ if (NULL==(s=H5H_peek (f, stab.heap_addr, ent->name_off))) {
+ HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, NULL);
}
- for (hash_ent=hash->head; hash_ent; hash_ent=hash_ent->next) {
+ shadow->name = H5MM_xstrdup (s);
+ }
+
+ /*
+ * Build the new shadow.
+ */
+ ent->shadow = shadow;
+ shadow->main = ent;
+ shadow->nrefs = 1;
+ shadow->entry = *ent;
+ shadow->entry.dirty = FALSE;
+ shadow->dir_addr = dir_addr;
+
+ /*
+ * Link it into the shadow heap
+ */
+ idx = dir_addr % f->nshadows;
+ for (hash=f->shadow[idx]; hash; hash=hash->next) {
+ if (hash->dir_addr==dir_addr) break;
+ }
+ if (!hash) {
+ hash = H5MM_xcalloc (1, sizeof(H5G_hash_t));
+ hash->dir_addr = dir_addr;
+ hash->next = f->shadow[idx];
+ f->shadow[idx] = hash;
+ if (hash->next) hash->next->prev = hash;
+ }
+ if (hash->head) {
+ for (hash_ent=hash->head,prev_ent=NULL;
+ hash_ent;
+ hash_ent=hash_ent->next) {
if (strcmp (shadow->name, hash_ent->name)<0) break;
+ prev_ent = hash_ent;
}
if (hash_ent) {
+ /* Insert SHADOW before HASH_ENT */
if (hash_ent->prev) hash_ent->prev->next = shadow;
else hash->head = shadow;
shadow->prev = hash_ent->prev;
shadow->next = hash_ent;
hash_ent->prev = shadow;
} else {
- hash->head = shadow;
+ /* Append SHADOW to list */
+ assert (prev_ent && NULL==prev_ent->next);
+ prev_ent->next = shadow;
+ shadow->prev = prev_ent;
}
+ } else {
+ /* Insert shadow at head of list */
+ shadow->next = hash->head;
+ if (hash->head) hash->head->prev = shadow;
+ hash->head = shadow;
}
+#ifdef DEBUG_SHADOWS
+ H5G_shadow_check (f);
+#endif
+
ret_value = &(shadow->entry);
done:
@@ -423,8 +532,8 @@ H5G_shadow_close (hdf5_file_t *f, H5G_entry_t *ent)
H5G_shadow_dissociate (ent);
/* find symtabs shadow list */
- idx = shadow->dir_addr % H5G_NSHADOWS;
- for (hash=H5G_shadow_g[idx]; hash; hash=hash->next) {
+ idx = shadow->dir_addr % f->nshadows;
+ for (hash=f->shadow[idx]; hash; hash=hash->next) {
if (hash->dir_addr==shadow->dir_addr) break;
}
assert (hash);
@@ -445,7 +554,7 @@ H5G_shadow_close (hdf5_file_t *f, H5G_entry_t *ent)
/* remove symtab's shadow list if empty */
if (!hash->head) {
if (hash->prev) hash->prev->next = hash->next;
- else H5G_shadow_g[idx] = hash->next;
+ else f->shadow[idx] = hash->next;
if (hash->next) hash->next->prev = hash->prev;
H5MM_xfree (hash);
}
@@ -453,3 +562,153 @@ H5G_shadow_close (hdf5_file_t *f, H5G_entry_t *ent)
FUNC_LEAVE (SUCCEED);
}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_move
+ *
+ * Purpose: Moves the SHADOW for some entry to correspond to a
+ * NEW_ENTRY. The DIR_ADDR is the address for the directory
+ * which contains NEW_ENTRY.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Friday, September 19, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_shadow_move (hdf5_file_t *f, H5G_shadow_t *shadow, const char *new_name,
+ H5G_entry_t *new_entry, haddr_t dir_addr)
+{
+ H5G_hash_t *hash;
+ uintn idx;
+
+ FUNC_ENTER (H5G_shadow_move, NULL, FAIL);
+
+ assert (shadow);
+ assert (new_entry);
+ assert (dir_addr>0);
+
+ if (0==shadow->dir_addr) {
+ /*
+ * We're moving the shadow for the root object. This simplifies things
+ * greatly since it implies that this is the only shadow currently
+ * defined for the entire file.
+ */
+ idx = dir_addr % f->nshadows;
+ assert (NULL==f->shadow[idx]); /*Nothing at new idx... */
+ hash = f->shadow[0];
+ assert (hash); /*..but root idx has something. */
+ assert (0==hash->dir_addr); /*..and it's the root something */
+ assert (NULL==hash->next); /*..and just that */
+ assert (hash->head==shadow); /*..and exactly that */
+
+ /* Move root entry to new hash bucket */
+ f->shadow[idx] = hash;
+ f->shadow[0] = NULL;
+ hash->dir_addr = dir_addr;
+
+ /* Associate SHADOW with NEW_ENTRY */
+ shadow->dir_addr = dir_addr;
+ shadow->main = new_entry;
+ new_entry->shadow = shadow;
+
+ /* Give the shadow a new name */
+ H5MM_xfree (shadow->name);
+ shadow->name = H5MM_xstrdup (new_name);
+
+ } else {
+ /*
+ * Other shadows never move.
+ */
+ assert (shadow->dir_addr==dir_addr);
+ shadow->main = new_entry;
+ new_entry->shadow = shadow;
+ }
+
+ FUNC_LEAVE (SUCCEED);
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_flush
+ *
+ * Purpose: Flush all open object information to the main cache.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL if INVALIDATE is non-zero and there are
+ * open objects.
+ *
+ * Programmer: Robb Matzke
+ * Friday, September 19, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_shadow_flush (hdf5_file_t *f, hbool_t invalidate)
+{
+ uintn idx;
+ H5G_hash_t *hash = NULL;
+ H5G_shadow_t *shadow = NULL;
+ intn nfound=0;
+
+ FUNC_ENTER (H5G_shadow_flush, NULL, FAIL);
+
+ for (idx=0; idx<f->nshadows; idx++) {
+ for (hash=f->shadow[idx]; hash; hash=hash->next) {
+ for (shadow=hash->head; shadow; shadow=shadow->next) {
+ if (!shadow->main &&
+ NULL==H5G_stab_find (f, shadow->dir_addr, NULL,
+ shadow->name)) {
+ HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL);
+ }
+ assert (shadow->main);
+ *(shadow->main) = shadow->entry;
+ shadow->entry.dirty = FALSE;
+ nfound++;
+
+#ifndef NDEBUG
+ /*
+ * This is usually a bad thing--an hdf5 programmer forgot to
+ * close some object before closing the file. Since this is hard
+ * to debug, we'll be nice and print the names here. We don't
+ * know the full name, but we'll print the file address (relative
+ * to the boot block) of the object header for the directory that
+ * contains the open object.
+ */
+ if (invalidate) {
+ fprintf (stderr, "Open object <%lu>/%s",
+ (unsigned long)(shadow->dir_addr),
+ shadow->name);
+ if (shadow->nrefs>1) {
+ fprintf (stderr, " (%d times)", shadow->nrefs);
+ }
+ fputc ('\n', stderr);
+ }
+#endif
+ }
+ }
+ }
+
+ if (invalidate && nfound) {
+ /*
+ * No clean easy way to do this, just leak the memory. If we free a
+ * shadow and then something else tries to access it (perhaps to close
+ * it) then they trample on freed memory.
+ */
+ HRETURN_ERROR (H5E_SYM, H5E_UNSUPPORTED, FAIL);
+ }
+
+ FUNC_LEAVE (SUCCEED);
+}