summaryrefslogtreecommitdiffstats
path: root/src/H5Gshad.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Gshad.c')
-rw-r--r--src/H5Gshad.c460
1 files changed, 460 insertions, 0 deletions
diff --git a/src/H5Gshad.c b/src/H5Gshad.c
new file mode 100644
index 0000000..5de4b29
--- /dev/null
+++ b/src/H5Gshad.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 1997 National Center for Supercomputing Applications.
+ * All rights reserved.
+ *
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Thursday, September 18, 1997
+ */
+#define H5G_PACKAGE /*suppress error message about including H5Gpkg.h*/
+
+#include <H5private.h> /*library */
+#include <H5Eprivate.h> /*error handling */
+#include <H5Gpkg.h> /*symbol tables */
+#include <H5Hprivate.h> /*heap functions */
+#include <H5MMprivate.h> /*memory management */
+#include <H5Oprivate.h> /*object header messages */
+
+#define PABLO_MASK H5G_shadow_mask
+
+/* 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;
+ struct H5G_hash_t *next;
+ struct H5G_hash_t *prev;
+} H5G_hash_t;
+
+static H5G_hash_t *H5G_shadow_g[H5G_NSHADOWS];
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_p
+ *
+ * Purpose: Determines if ENT is a shadow or a real symbol table entry.
+ *
+ * Return: Success: Non-zero if ENT is a shadow; zero otherwise.
+ *
+ * Failure: FALSE
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 18, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+hbool_t
+H5G_shadow_p (H5G_entry_t *ent)
+{
+ H5G_shadow_t tmp;
+ size_t delta = (char*)&(tmp.entry) - (char*)&tmp;
+ hbool_t ret_value = FALSE;
+
+ FUNC_ENTER (H5G_shadow_p, NULL, FALSE);
+
+ if (!ent || !ent->shadow) return FALSE;
+ ret_value = ((char*)ent - (char*)(ent->shadow) == delta);
+
+ FUNC_LEAVE (ret_value);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_dissociate
+ *
+ * Purpose: Removes the association between a shadow and its entry or an
+ * entry and its shadow. The ENT argument can be a shadow or a
+ * cached entry.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 18, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_shadow_dissociate (H5G_entry_t *ent)
+{
+ FUNC_ENTER (H5G_shadow_dissociate, NULL, FAIL);
+
+ if (H5G_shadow_p (ent)) {
+ if (ent->shadow->main) {
+ ent->shadow->main->shadow = NULL;
+ ent->shadow->main = NULL;
+ }
+ } else if (ent && ent->shadow) {
+ ent->shadow->main = NULL;
+ ent->shadow = NULL;
+ }
+
+ FUNC_LEAVE (SUCCEED);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_sync
+ *
+ * Purpose: Synchronizes a shadow with an entry by copying the
+ * shadow contents to the entry if the shadow is dirty,
+ * and then clearing the shadow dirty bit. You may call this
+ * function with either a shadow or a real entry.
+ *
+ * If ENT is a shadow, then the shadow is synchronized only if
+ * the entry is currently cached.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 18, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_shadow_sync (H5G_entry_t *ent)
+{
+ H5G_shadow_t *shadow = NULL;
+ FUNC_ENTER (H5G_shadow_sync, NULL, FAIL);
+
+ /*
+ * If the caller supplied us with a shadow instead of the main entry, then
+ * adjust the arguments.
+ */
+ if (H5G_shadow_p (ent)) {
+ shadow = ent->shadow;
+ ent = shadow->main;
+ } else {
+ shadow = ent->shadow;
+ }
+
+ if (shadow && shadow->entry.dirty) {
+ if (!ent) {
+ /* Main entry is not cached */
+ HRETURN_ERROR (H5E_SYM, H5E_NOTCACHED, FAIL);
+ }
+ *ent = shadow->entry;
+ shadow->entry.dirty = FALSE;
+ }
+ FUNC_LEAVE (SUCCEED);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_list
+ *
+ * Purpose: Returns a doubly linked list of shadows for the symbol
+ * table whose header address is DIR_ADDR.
+ *
+ * Return: Success: Ptr shadow list or null.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 17, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_shadow_t *
+H5G_shadow_list (haddr_t dir_addr)
+{
+ uintn idx = dir_addr % H5G_NSHADOWS;
+ H5G_hash_t *bucket = NULL;
+
+ FUNC_ENTER (H5G_shadows, NULL, NULL);
+
+ for (bucket=H5G_shadow_g[idx]; bucket; bucket=bucket->next) {
+ if (bucket->dir_addr==dir_addr) {
+ HRETURN (bucket->head);
+ }
+ }
+ FUNC_LEAVE (NULL);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_assoc_node
+ *
+ * Purpose: Given a new symbol table node and a symbol table header
+ * address, associate entries in that node with their shadow if
+ * they have one.
+ *
+ * SYM must be an uncached or protected symbol table node.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL, if an error occurs then none of the
+ * entries are associated with shadows.
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 17, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_shadow_assoc_node (hdf5_file_t *f, H5G_node_t *sym, H5G_entry_t *self)
+{
+ H5G_shadow_t *shadow = NULL;
+ H5O_stab_t stab;
+ const char *s = NULL;
+ intn i = 0;
+
+ FUNC_ENTER (H5G_shadow_assoc_node, NULL, FAIL);
+
+ /* Check arguments */
+ assert (f); /* The file */
+ assert (sym); /* The symbol table node */
+ assert (self); /* The symbol table header info */
+
+ if ((shadow=H5G_shadow_list (self->header))) {
+
+ /* We need the heap address so we can see the symbol names */
+ if (NULL==H5O_read (f, self->header, self, H5O_NAME, 0, &stab)) {
+ HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL);
+ }
+
+ while (i<sym->nsyms && shadow) {
+
+ /* Advance the Entry ptr until it gets to the next shadow. */
+ while (i<sym->nsyms &&
+ (s=H5H_peek (f, stab.heap_addr, sym->entry[i].name_off)) &&
+ strcmp (s, shadow->name)<0) i++;
+
+ /* Advance the Shadow ptr until it gets to the next entry. */
+ while (i<sym->nsyms && s && shadow &&
+ strcmp (s, shadow->name)>0) shadow = shadow->next;
+
+ /* Did we find a match? */
+ if (i<sym->nsyms && s && shadow && !strcmp (s, shadow->name)) {
+ shadow->main = sym->entry + i;
+ sym->entry[i].shadow = shadow;
+ }
+ }
+ }
+
+ FUNC_LEAVE (SUCCEED);
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_open
+ *
+ * Purpose: Given a handle to an already open object, or given a
+ * pointer to the cached symbol table entry for that
+ * object, open the object (again) and return a handle
+ * to it.
+ *
+ * Return: Success: Handle to open object
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 18, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5G_entry_t *
+H5G_shadow_open (hdf5_file_t *f, H5G_entry_t *dir, H5G_entry_t *ent)
+{
+ H5G_shadow_t *shadow = NULL;
+ H5O_stab_t stab;
+ const char *s = NULL;
+ H5G_hash_t *hash = NULL;
+ H5G_shadow_t *hash_ent = NULL;
+ uintn idx;
+ H5O_name_t name_mesg = {NULL};
+ H5G_entry_t *ret_value = NULL;
+
+ FUNC_ENTER (H5G_shadow_open, NULL, NULL);
+
+ /* check args */
+ assert (f);
+ assert (dir);
+ assert (ent);
+
+ if (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");
+ }
+
+ } 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);
+ }
+
+ /*
+ * Build the new shadow.
+ */
+ ent->shadow = shadow;
+ shadow->main = ent;
+ shadow->nrefs = 1;
+ shadow->entry = *ent;
+ shadow->entry.dirty = FALSE;
+ shadow->dir_addr = dir->header;
+
+ /*
+ * Link it into the shadow heap
+ */
+ idx = dir->header % H5G_NSHADOWS;
+ for (hash=H5G_shadow_g[idx]; hash; hash=hash->next) {
+ if (hash->dir_addr==dir->header) break;
+ }
+ 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;
+ }
+ for (hash_ent=hash->head; hash_ent; hash_ent=hash_ent->next) {
+ if (strcmp (shadow->name, hash_ent->name)<0) break;
+ }
+ if (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;
+ }
+ }
+
+ ret_value = &(shadow->entry);
+
+ done:
+ if (!ret_value) {
+ if (shadow) {
+ H5MM_xfree (shadow->name);
+ H5MM_xfree (shadow);
+ }
+ }
+
+ FUNC_LEAVE (ret_value);
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5G_shadow_close
+ *
+ * Purpose: Closes an open object.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, September 18, 1997
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_shadow_close (hdf5_file_t *f, H5G_entry_t *ent)
+{
+ uintn idx;
+ H5G_hash_t *hash=NULL;
+ H5G_shadow_t *hash_ent=NULL, *shadow=NULL;
+
+ FUNC_ENTER (H5G_shadow_close, NULL, FAIL);
+
+ /* check args */
+ assert (ent);
+ assert (H5G_shadow_p (ent));
+ assert (ent->shadow->nrefs>0);
+ shadow = ent->shadow;
+
+ /* clean the shadow */
+ if (1==shadow->nrefs && ent->dirty) {
+ 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) = *ent;
+ ent->dirty = FALSE;
+ }
+
+ /* close */
+ shadow->nrefs -= 1;
+
+ if (0==shadow->nrefs) {
+ /* dissociate shadow and entry */
+ H5G_shadow_dissociate (ent);
+
+ /* find symtabs shadow list */
+ idx = shadow->dir_addr % H5G_NSHADOWS;
+ for (hash=H5G_shadow_g[idx]; hash; hash=hash->next) {
+ if (hash->dir_addr==shadow->dir_addr) break;
+ }
+ assert (hash);
+
+ /* find shadow in shadow list */
+ for (hash_ent=hash->head; hash_ent; hash_ent=hash_ent->next) {
+ if (hash_ent==shadow) break;
+ }
+ assert (hash_ent);
+
+ /* remove shadow from shadow list */
+ if (hash_ent->prev) hash_ent->prev->next = hash_ent->next;
+ else hash->head = hash_ent->next;
+ if (hash_ent->next) hash_ent->next->prev = hash_ent->prev;
+ H5MM_xfree (shadow->name);
+ H5MM_xfree (shadow);
+
+ /* 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;
+ if (hash->next) hash->next->prev = hash->prev;
+ H5MM_xfree (hash);
+ }
+ }
+
+ FUNC_LEAVE (SUCCEED);
+}