summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2003-04-14 05:03:26 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2003-04-14 05:03:26 (GMT)
commitaa1cedb4f8b57fa73ab385d6316073a497410244 (patch)
treef1070fa6203d1b5ed7d2f3056f1fe83c01c4a315
parent4e4bdd91633a24a39450a236cc88ab7a3b3a17d4 (diff)
downloadhdf5-aa1cedb4f8b57fa73ab385d6316073a497410244.zip
hdf5-aa1cedb4f8b57fa73ab385d6316073a497410244.tar.gz
hdf5-aa1cedb4f8b57fa73ab385d6316073a497410244.tar.bz2
[svn-r6658] Purpose:
New feature Description: Track changes in the internal metadata API with clearing the metadata dirty flag without flushing object. Added ability to delete an object header in the file and restore all the space referenced by various header messages. Platforms tested: FreeBSD 4.8 (sleipnir) w/C++ Linux 2.4 (burrwhite) w/FORTRAN Solaris 2.7 (arabica) w/FORTRAN IRIX64 6.5 (modi4) w/parallel & FORTRAN (h5committest not run due to my ongoing difficulties with C++ on burrwhite).
-rw-r--r--src/H5O.c224
-rw-r--r--src/H5Olayout.c58
-rw-r--r--src/H5Opkg.h5
-rw-r--r--src/H5Ostab.c39
4 files changed, 308 insertions, 18 deletions
diff --git a/src/H5O.c b/src/H5O.c
index 7ef590c..814eda3 100644
--- a/src/H5O.c
+++ b/src/H5O.c
@@ -48,10 +48,6 @@
/* PRIVATE PROTOTYPES */
static herr_t H5O_init(H5F_t *f, hid_t dxpl_id, size_t size_hint,
H5G_entry_t *ent/*out*/, haddr_t header);
-static H5O_t *H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_udata1,
- void *_udata2);
-static herr_t H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_t *oh);
-static herr_t H5O_dest(H5F_t *f, H5O_t *oh);
static herr_t H5O_reset_real(const H5O_class_t *type, void *native);
static void * H5O_free_real(const H5O_class_t *type, void *mesg);
static void * H5O_copy_real(const H5O_class_t *type, const void *mesg,
@@ -79,6 +75,14 @@ static unsigned H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_class_t *type,
size_t size);
static unsigned H5O_alloc_extend_chunk(H5O_t *oh, unsigned chunkno, size_t size);
static unsigned H5O_alloc_new_chunk(H5F_t *f, H5O_t *oh, size_t size);
+static herr_t H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh);
+
+/* Metadata cache callbacks */
+static H5O_t *H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_udata1,
+ void *_udata2);
+static herr_t H5O_flush(H5F_t *f, hid_t dxpl_id, hbool_t destroy, haddr_t addr, H5O_t *oh);
+static herr_t H5O_dest(H5F_t *f, H5O_t *oh);
+static herr_t H5O_clear(H5O_t *oh);
/* H5O inherits cache-like properties from H5AC */
static const H5AC_class_t H5AC_OHDR[1] = {{
@@ -86,6 +90,7 @@ static const H5AC_class_t H5AC_OHDR[1] = {{
(H5AC_load_func_t)H5O_load,
(H5AC_flush_func_t)H5O_flush,
(H5AC_dest_func_t)H5O_dest,
+ (H5AC_clear_func_t)H5O_clear,
}};
/* Interface initialization */
@@ -503,7 +508,7 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
UINT32DECODE(p, oh->nlink);
/* decode first chunk info */
- chunk_addr = addr + (hsize_t)H5O_SIZEOF_HDR(f);
+ chunk_addr = addr + (hsize_t)hdr_size;
UINT32DECODE(p, chunk_size);
/* build the message array */
@@ -840,7 +845,47 @@ H5O_dest(H5F_t UNUSED *f, H5O_t *oh)
H5FL_FREE(H5O_t,oh);
FUNC_LEAVE_NOAPI(SUCCEED);
-}
+} /* end H5O_dest() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_clear
+ *
+ * Purpose: Mark a object header in memory as non-dirty.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 20 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_clear(H5O_t *oh)
+{
+ unsigned u; /* Local index variable */
+
+ FUNC_ENTER_NOINIT(H5O_clear);
+
+ /* check args */
+ assert(oh);
+
+ /* Mark chunks as clean */
+ for (u = 0; u < oh->nchunks; u++)
+ oh->chunk[u].dirty=FALSE;
+
+ /* Mark messages as clean */
+ for (u = 0; u < oh->nmesgs; u++)
+ oh->mesg[u].dirty=FALSE;
+
+ /* Mark whole header as clean */
+ oh->cache_info.dirty=FALSE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED);
+} /* end H5O_clear() */
/*-------------------------------------------------------------------------
@@ -1114,6 +1159,7 @@ int
H5O_link(H5G_entry_t *ent, int adjust, hid_t dxpl_id)
{
H5O_t *oh = NULL;
+ hbool_t deleted=FALSE; /* Whether the object was deleted as a result of this action */
int ret_value = FAIL;
FUNC_ENTER_NOAPI(H5O_link, FAIL);
@@ -1136,6 +1182,24 @@ H5O_link(H5G_entry_t *ent, int adjust, hid_t dxpl_id)
HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "link count would be negative");
oh->nlink += adjust;
oh->cache_info.dirty = TRUE;
+
+ /* Check if the object should be deleted */
+ if(oh->nlink==0) {
+ /* Check if the object is still open by the user */
+ if(H5FO_opened(ent->file,ent->header)>=0) {
+ /* Flag the object to be deleted when it's closed */
+ if(H5FO_mark(ent->file,ent->header)<0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't mark object for deletion");
+ } /* end if */
+ else {
+ /* Delete object right now */
+ if(H5O_delete_oh(ent->file,dxpl_id,oh)<0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file");
+
+ /* Mark the object header as deleted */
+ deleted=TRUE;
+ } /* end else */
+ } /* end if */
} else if (adjust>0) {
oh->nlink += adjust;
oh->cache_info.dirty = TRUE;
@@ -1145,7 +1209,7 @@ H5O_link(H5G_entry_t *ent, int adjust, hid_t dxpl_id)
ret_value = oh->nlink;
done:
- if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh) < 0 && ret_value>=0)
+ if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, deleted) < 0 && ret_value>=0)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
FUNC_LEAVE_NOAPI(ret_value);
@@ -1505,7 +1569,7 @@ H5O_read_real(H5G_entry_t *ent, const H5O_class_t *type, int sequence, void *mes
}
done:
- if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh) < 0 && ret_value!=NULL)
+ if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 0 && ret_value!=NULL)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, NULL, "unable to release object header");
FUNC_LEAVE_NOAPI(ret_value);
@@ -1834,7 +1898,7 @@ H5O_modify_real(H5G_entry_t *ent, const H5O_class_t *type, int overwrite,
ret_value = sequence;
done:
- if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh) < 0 && ret_value!=FAIL)
+ if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 0 && ret_value!=FAIL)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
FUNC_LEAVE_NOAPI(ret_value);
@@ -1916,7 +1980,7 @@ H5O_unprotect(H5G_entry_t *ent, H5O_t *oh, hid_t dxpl_id)
assert(H5F_addr_defined(ent->header));
assert(oh);
- if (H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh) < 0)
+ if (H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 0)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
done:
@@ -2206,7 +2270,7 @@ H5O_touch(H5G_entry_t *ent, hbool_t force, hid_t dxpl_id)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to update object modificaton time");
done:
- if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh)<0 && ret_value>=0)
+ if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE)<0 && ret_value>=0)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
FUNC_LEAVE_NOAPI(ret_value);
@@ -2310,7 +2374,7 @@ H5O_bogus(H5G_entry_t *ent, hid_t dxpl_id)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to update object 'bogus' message");
done:
- if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh)<0)
+ if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE)<0)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
FUNC_LEAVE(ret_value);
@@ -2466,7 +2530,7 @@ H5O_remove_real(H5G_entry_t *ent, const H5O_class_t *type, int sequence, hid_t d
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to remove constant message(s)");
done:
- if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh) < 0 && ret_value>=0)
+ if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 0 && ret_value>=0)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
FUNC_LEAVE_NOAPI(ret_value);
@@ -3018,6 +3082,138 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5O_delete
+ *
+ * Purpose: Delete an object header from a file. This frees the file
+ * space used for the object header (and it's continuation blocks)
+ * and also walks through each header message and asks it to
+ * remove all the pieces of the file referenced by the header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 19 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr)
+{
+ H5O_t *oh=NULL; /* Object header information */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5O_delete,FAIL);
+
+ /* Check args */
+ assert (f);
+ assert(H5F_addr_defined(addr));
+
+ /* Get the object header information */
+ if (NULL == (oh = H5AC_protect(f, dxpl_id, H5AC_OHDR, addr, NULL, NULL)))
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
+
+ /* Delete object */
+ if(H5O_delete_oh(f,dxpl_id,oh)<0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file");
+
+done:
+ if (oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, TRUE)<0 && ret_value>=0)
+ HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_delete() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_delete_oh
+ *
+ * Purpose: Internal function to:
+ * Delete an object header from a file. This frees the file
+ * space used for the object header (and it's continuation blocks)
+ * and also walks through each header message and asks it to
+ * remove all the pieces of the file referenced by the header.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@ncsa.uiuc.edu
+ * Mar 19 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh)
+{
+ H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
+ H5O_chunk_t *curr_chk; /* Pointer to current chunk being operated on */
+ unsigned u;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOINIT(H5O_delete_oh);
+
+ /* Check args */
+ assert (f);
+ assert (oh);
+
+ /* Walk through the list of object header messages, asking each on to
+ * delete any file space used
+ */
+ for (u = 0, curr_msg=&oh->mesg[0]; u < oh->nmesgs; u++,curr_msg++) {
+ const H5O_class_t *type = NULL;
+
+ /* Don't handle shared messages yet */
+ assert(!(curr_msg->flags & H5O_FLAG_SHARED));
+
+ /* Get the message's type */
+ type = curr_msg->type;
+
+ /* Check if there is a file space deletion callback for this type of message */
+ if(type->delete) {
+ /*
+ * Decode the message if necessary.
+ */
+ if (NULL == curr_msg->native) {
+ assert(type->decode);
+ curr_msg->native = (type->decode) (f, dxpl_id, curr_msg->raw, NULL);
+ if (NULL == curr_msg->native)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode message");
+ } /* end if */
+
+ if ((type->delete)(f, dxpl_id, curr_msg->native)<0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message");
+ } /* end if */
+ } /* end for */
+
+ /* Free all the chunks for the object header */
+ for (u = 0, curr_chk=&oh->chunk[0]; u < oh->nchunks; u++,curr_chk++) {
+ haddr_t chk_addr; /* Actual address of chunk */
+ hsize_t chk_size; /* Actual size of chunk */
+
+ if(u==0) {
+ chk_addr = curr_chk->addr - H5O_SIZEOF_HDR(f);
+ chk_size = curr_chk->size + H5O_SIZEOF_HDR(f);
+ } /* end if */
+ else {
+ chk_addr = curr_chk->addr;
+ chk_size = curr_chk->size;
+ } /* end else */
+
+ /* Free the file space for the chunk */
+ if (H5MF_xfree(f, H5FD_MEM_OHDR, dxpl_id, chk_addr, chk_size)<0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free object header");
+ } /* end for */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_delete_oh() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5O_debug_id
*
* Purpose: Act as a proxy for calling the 'debug' method for a
@@ -3238,7 +3434,7 @@ H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int f
HDfprintf(stream, "*** TOTAL SIZE DOES NOT MATCH ALLOCATED SIZE!\n");
done:
- if (oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh) < 0 && ret_value>=0)
+ if (oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, FALSE) < 0 && ret_value>=0)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header");
FUNC_LEAVE_NOAPI(ret_value);
diff --git a/src/H5Olayout.c b/src/H5Olayout.c
index 43d1df7..fc1eeae 100644
--- a/src/H5Olayout.c
+++ b/src/H5Olayout.c
@@ -24,6 +24,7 @@
#include "H5Dprivate.h"
#include "H5Eprivate.h"
#include "H5FLprivate.h" /*Free Lists */
+#include "H5MFprivate.h" /* File space management */
#include "H5MMprivate.h"
#include "H5Opkg.h" /* Object header functions */
@@ -34,6 +35,7 @@ static void *H5O_layout_copy(const void *_mesg, void *_dest);
static size_t H5O_layout_size(H5F_t *f, const void *_mesg);
static herr_t H5O_layout_reset (void *_mesg);
static herr_t H5O_layout_free (void *_mesg);
+static herr_t H5O_layout_delete(H5F_t *f, hid_t dxpl_id, const void *_mesg);
static herr_t H5O_layout_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg, FILE * stream,
int indent, int fwidth);
@@ -47,7 +49,8 @@ const H5O_class_t H5O_LAYOUT[1] = {{
H5O_layout_copy, /*copy the native value */
H5O_layout_size, /*size of message on disk */
H5O_layout_reset, /*reset method */
- H5O_layout_free, /*free the struct */
+ H5O_layout_free, /*free the struct */
+ H5O_layout_delete, /* file delete method */
NULL, /*get share method */
NULL, /*set share method */
H5O_layout_debug, /*debug the message */
@@ -444,6 +447,59 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5O_layout_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, March 19, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_layout_delete(H5F_t *f, hid_t dxpl_id, const void *_mesg)
+{
+ const H5O_layout_t *mesg = (const H5O_layout_t *) _mesg;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5O_layout_delete, FAIL);
+
+ /* check args */
+ assert(f);
+ assert(mesg);
+
+ /* Perform different actions, depending on the type of storage */
+ switch(mesg->type) {
+ case H5D_COMPACT: /* Compact data storage */
+ /* Nothing required */
+ break;
+
+ case H5D_CONTIGUOUS: /* Contiguous block on disk */
+ /* Free the file space for the raw data */
+ if (H5F_contig_delete(f, dxpl_id, mesg)<0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free raw data");
+ break;
+
+ case H5D_CHUNKED: /* Chunked blocks on disk */
+ /* Free the file space for the raw data */
+ if (H5F_istore_delete(f, dxpl_id, mesg)<0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free raw data");
+ break;
+
+ default:
+ HGOTO_ERROR (H5E_OHDR, H5E_BADTYPE, FAIL, "not valid storage type");
+ } /* end switch */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_layout_delete() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5O_layout_debug
*
* Purpose: Prints debugging info for a message.
diff --git a/src/H5Opkg.h b/src/H5Opkg.h
index 2ca5a96..ceb4ae3 100644
--- a/src/H5Opkg.h
+++ b/src/H5Opkg.h
@@ -66,8 +66,9 @@ typedef struct H5O_class_t {
size_t (*raw_size)(H5F_t*, const void*);/*sizeof raw val */
herr_t (*reset)(void *); /*free nested data structs */
herr_t (*free)(void *); /*free main data struct */
- herr_t (*get_share)(H5F_t*, const void*, struct H5O_shared_t*);
- herr_t (*set_share)(H5F_t*, void*, const struct H5O_shared_t*);
+ herr_t (*delete)(H5F_t *, hid_t, const void *); /* Delete space in file referenced by this message */
+ herr_t (*get_share)(H5F_t*, const void*, struct H5O_shared_t*); /* Get shared information */
+ herr_t (*set_share)(H5F_t*, void*, const struct H5O_shared_t*); /* Set shared information */
herr_t (*debug)(H5F_t*, hid_t, const void*, FILE*, int, int);
} H5O_class_t;
diff --git a/src/H5Ostab.c b/src/H5Ostab.c
index 3258964..17986c1 100644
--- a/src/H5Ostab.c
+++ b/src/H5Ostab.c
@@ -42,6 +42,7 @@ static herr_t H5O_stab_encode(H5F_t *f, uint8_t *p, const void *_mesg);
static void *H5O_stab_copy(const void *_mesg, void *_dest);
static size_t H5O_stab_size(H5F_t *f, const void *_mesg);
static herr_t H5O_stab_free (void *_mesg);
+static herr_t H5O_stab_delete(H5F_t *f, hid_t dxpl_id, const void *_mesg);
static herr_t H5O_stab_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
FILE * stream, int indent, int fwidth);
@@ -55,7 +56,8 @@ const H5O_class_t H5O_STAB[1] = {{
H5O_stab_copy, /*copy the native value */
H5O_stab_size, /*size of symbol table entry */
NULL, /*default reset method */
- H5O_stab_free, /* free method */
+ H5O_stab_free, /* free method */
+ H5O_stab_delete, /* file delete method */
NULL, /*get share method */
NULL, /*set share method */
H5O_stab_debug, /*debug the message */
@@ -313,6 +315,41 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5O_stab_delete
+ *
+ * Purpose: Free file space referenced by message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, March 20, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_stab_delete(H5F_t *f, hid_t dxpl_id, const void *_mesg)
+{
+ const H5O_stab_t *stab = (const H5O_stab_t *) _mesg;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5O_stab_delete, FAIL);
+
+ /* check args */
+ assert(f);
+ assert(stab);
+
+ /* Free the file space for the symbol table */
+ if (H5G_stab_delete(f, dxpl_id, stab->btree_addr, stab->heap_addr)<0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free symbol table");
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5O_stab_delete() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5O_stab_debug
*
* Purpose: Prints debugging info for a symbol table message.