summaryrefslogtreecommitdiffstats
path: root/src/H5SM.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5SM.c')
-rwxr-xr-xsrc/H5SM.c997
1 files changed, 997 insertions, 0 deletions
diff --git a/src/H5SM.c b/src/H5SM.c
new file mode 100755
index 0000000..c17dd16
--- /dev/null
+++ b/src/H5SM.c
@@ -0,0 +1,997 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#define H5SM_PACKAGE /*suppress error about including H5SMpkg */
+#define H5F_PACKAGE /*suppress error about including H5Fpkg */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5ACprivate.h" /* Metadata cache */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5MFprivate.h" /* File memory management */
+#include "H5MMprivate.h" /* Memory management */
+
+#include "H5Fpkg.h" /* File access */
+#include "H5SMpkg.h" /* Shared object header messages */
+
+/****************/
+/* Local Macros */
+/****************/
+/* Values used to create the SOHM heaps */
+#define H5SM_FHEAP_MAN_WIDTH 4
+#define H5SM_FHEAP_MAN_START_BLOCK_SIZE 1024
+#define H5SM_FHEAP_MAN_MAX_DIRECT_SIZE (64 * 1024)
+#define H5SM_FHEAP_MAN_MAX_INDEX 20
+#define H5SM_FHEAP_MAN_START_ROOT_ROWS 1
+#define H5SM_FHEAP_CHECKSUM_DBLOCKS TRUE
+#define H5SM_FHEAP_MAX_MAN_SIZE (4 * 1024)
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/********************/
+/* Local Prototypes */
+/********************/
+static herr_t H5SM_create_index(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id);
+/* JAMES
+static herr_t H5SM_write_index(H5F_t *f, haddr_t index_addr, hsize_t sohm_hash, haddr_t sohm_addr, hid_t dxpl_id);
+*/
+static haddr_t H5SM_create_list(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id);
+static herr_t H5SM_write_mesg(H5F_t *f, hid_t dxpl_id, H5SM_index_header_t *header,
+ unsigned type_id, void *mesg, unsigned *cache_flags_ptr);
+static herr_t H5SM_delete_from_index(H5F_t *f, hid_t dxpl_id,
+ H5SM_index_header_t *header, unsigned type_id, const H5O_shared_t * mesg,
+ unsigned *cache_flags);
+static hsize_t H5SM_find_in_list(H5F_t *f, H5SM_list_t *list, const H5SM_mesg_key_t *key);
+static ssize_t H5SM_get_index(const H5SM_master_table_t *table, unsigned type_id);
+
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+H5FL_DEFINE(H5SM_master_table_t);
+H5FL_ARR_DEFINE(H5SM_index_header_t, H5SM_MAX_INDEXES);
+H5FL_DEFINE(H5SM_list_t);
+H5FL_ARR_DEFINE(H5SM_sohm_t, H5SM_MAX_LIST_ELEMS);
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_init
+ *
+ * Purpose: Initializes the Shared Message interface.
+ *
+ * Creates a master SOHM table in the file and in the cache.
+ * This function should not be called for files that have
+ * SOHMs disabled in the FCPL.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_init(H5F_t *f, H5P_genplist_t * fc_plist, hid_t dxpl_id)
+{
+ H5SM_master_table_t *table = NULL;
+ haddr_t table_addr = HADDR_UNDEF;
+ unsigned num_indexes;
+ size_t list_to_btree, btree_to_list;
+ unsigned index_type_flags[H5SM_MAX_NUM_INDEXES];
+ ssize_t x;
+ hsize_t table_size;
+ herr_t ret_value=SUCCEED;
+
+ FUNC_ENTER_NOAPI(H5SM_init, NULL)
+
+ HDassert(f);
+ /* File should not already have a SOHM table */
+ HDassert(f->shared->sohm_addr == HADDR_UNDEF);
+
+ /* Initialize master table */
+ if(NULL == (table = H5FL_MALLOC(H5SM_master_table_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for SOHM table")
+
+ /* Get information from fcpl */
+ if(H5P_get(fc_plist, H5F_CRT_SOHM_NINDEXES_NAME, &num_indexes)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get SOHM information")
+ if(H5P_get(fc_plist, H5F_CRT_INDEX_TYPES_NAME, &index_type_flags)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get SOHM information")
+ if(H5P_get(fc_plist, H5F_CRT_SOHM_L2B_NAME, &list_to_btree)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get SOHM information")
+ if(H5P_get(fc_plist, H5F_CRT_SOHM_B2L_NAME, &btree_to_list)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get SOHM information")
+
+ /* Right now we just use one byte to hold the number of indexes */
+ HDassert(num_indexes < 256);
+ table->num_indexes = num_indexes;
+
+ /* Check that list and btree cutoffs make sense. There can't be any
+ * values greater than the list max but less than the btree min; the
+ * list max has to be greater than or equal to one less than the btree
+ * min.
+ */
+ if(list_to_btree + 1 < btree_to_list)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "SOHM list max is less than btree min")
+
+ HDassert(table->num_indexes > 0 && table->num_indexes <= H5SM_MAX_NUM_INDEXES);
+
+ /* Allocate the SOHM indexes as an array. */
+ if(NULL == (table->indexes = H5FL_ARR_MALLOC(H5SM_index_header_t, table->num_indexes)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for SOHM indexes")
+
+ /* Initialize all of the indexes, but don't allocate space for them to
+ * hold messages until we actually need to write to them.
+ */
+ /* JAMES: currently all indexes use the same values */
+ for(x=0; x<table->num_indexes; x++)
+ {
+ table->indexes[x].btree_to_list = btree_to_list;
+ table->indexes[x].list_to_btree = list_to_btree;
+ table->indexes[x].mesg_types = index_type_flags[x];
+ table->indexes[x].index_addr = HADDR_UNDEF;
+ table->indexes[x].heap_addr = HADDR_UNDEF;
+ table->indexes[x].num_messages = 0;
+ /* Indexes start as lists unless the list-to-btree threshold is zero */
+ if(table->indexes[x].list_to_btree > 0) {
+ table->indexes[x].index_type = H5SM_LIST;
+ } else {
+ table->indexes[x].index_type = H5SM_BTREE;
+ }
+ } /* end for */
+
+ /* Allocate space for the table on disk */
+ table_size = (hsize_t) H5SM_TABLE_SIZE(f) + (hsize_t) (table->num_indexes * H5SM_INDEX_HEADER_SIZE(f));
+ if(HADDR_UNDEF == (table_addr = H5MF_alloc(f, H5FD_MEM_SOHM, dxpl_id, table_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for SOHM table")
+
+ /* Cache the new table */
+ if(H5AC_set(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, table, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, FAIL, "can't add SOHM table to cache")
+
+ /* Record the address of the master table in the file */
+ f->shared->sohm_addr = table_addr;
+
+done:
+ if(ret_value < 0)
+ {
+ if(table_addr != HADDR_UNDEF)
+ H5MF_xfree(f, H5FD_MEM_SOHM, dxpl_id, table_addr, (hsize_t)H5SM_TABLE_SIZE(f));
+ if(table != NULL)
+ H5FL_FREE(H5SM_master_table_t, table);
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_index
+ *
+ * Purpose: Get the index number for a given message type.
+ *
+ * Returns the number of the index in the supplied table
+ * that holds messages of type type_id, or negative if
+ * there is no index for this message type.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, October 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static ssize_t
+H5SM_get_index(const H5SM_master_table_t *table, unsigned type_id)
+{
+ ssize_t x;
+ unsigned type_flag;
+ hbool_t found = FALSE;
+ ssize_t ret_value = FAIL;
+
+ FUNC_ENTER_NOAPI(H5SM_get_index, FAIL)
+
+ /* Translate the H5O type_id into an H5SM type flag */
+ switch(type_id)
+ {
+ case H5O_SDSPACE_ID:
+ type_flag = H5SM_SDSPACE_FLAG;
+ break;
+ case H5O_DTYPE_ID:
+ type_flag = H5SM_DTYPE_FLAG;
+ break;
+ case H5O_FILL_NEW_ID:
+ type_flag = H5SM_FILL_FLAG;
+ break;
+ case H5O_PLINE_ID:
+ type_flag = H5SM_PLINE_FLAG;
+ break;
+ case H5O_ATTR_ID:
+ type_flag = H5SM_ATTR_FLAG;
+ break;
+ default:
+ HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "unknown message type ID")
+ }
+
+ /* Search the indexes until we find one that matches this flag or we've
+ * searched them all.
+ */
+ for(x=0; x<table->num_indexes && !found; ++x)
+ {
+ if(table->indexes[x].mesg_types & type_flag)
+ {
+ found = TRUE;
+ ret_value = x;
+ }
+ }
+
+ /* At this point, ret_value is either the location of the correct
+ * index or it's still FAIL because we didn't find an index.
+ */
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_fheap_addr
+ *
+ * Purpose: Gets the address of the fractal heap used to store
+ * messages of type type_id.
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, October 3, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+haddr_t
+H5SM_get_fheap_addr(H5F_t *f, unsigned type_id, hid_t dxpl_id)
+{
+ H5SM_master_table_t *table = NULL;
+ ssize_t index_num; /* Which index */
+ haddr_t ret_value;
+ FUNC_ENTER_NOAPI(H5SM_get_fheap_addr, FAIL)
+
+ /* Look up the master SOHM table */
+ if (NULL == (table = H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, f->shared->sohm_addr, NULL, NULL, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, HADDR_UNDEF, "unable to load SOHM master table")
+
+ /* JAMES! */
+ if((index_num = H5SM_get_index(table, type_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, HADDR_UNDEF, "unable to find correct SOHM index")
+
+ ret_value = table->indexes[index_num].heap_addr;
+
+done:
+ /* Release the master SOHM table */
+ if (table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, f->shared->sohm_addr, table, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, HADDR_UNDEF, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_create_index
+ *
+ * Purpose: Allocates storage for an index.
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_create_index(H5F_t *f, H5SM_index_header_t *header, hid_t dxpl_id)
+{
+ haddr_t list_addr=HADDR_UNDEF; /* Address of SOHM list */
+ haddr_t tree_addr=HADDR_UNDEF; /* Address of SOHM B-tree */
+ H5HF_create_t fheap_cparam; /* Fractal heap creation parameters */
+ H5HF_t *fheap = NULL;
+ size_t fheap_id_len; /* Size of a fractal heap ID */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI(H5SM_create_index, FAIL)
+
+ HDassert(header);
+ HDassert(header->index_addr == HADDR_UNDEF);
+ HDassert(header->btree_to_list <= header->list_to_btree);
+
+ /* In most cases, the index starts as a list */
+ if(header->list_to_btree > 0)
+ {
+ header->index_type = H5SM_LIST;
+
+ if((list_addr = H5SM_create_list(f, header, dxpl_id)) == HADDR_UNDEF) /* JAMES: only allocate part of the list? */
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTCREATE, FAIL, "list creation failed for SOHM index")
+
+ header->index_addr = list_addr;
+ }
+ else /* index is a B-tree */
+ {
+ header->index_type = H5SM_BTREE;
+
+ if(H5B2_create(f, dxpl_id, H5SM_INDEX, H5SM_B2_NODE_SIZE,
+ H5SM_SOHM_ENTRY_SIZE(f), H5SM_B2_SPLIT_PERCENT,
+ H5SM_B2_MERGE_PERCENT, &tree_addr) <0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTCREATE, FAIL, "B-tree creation failed for SOHM index")
+
+ header->index_addr = tree_addr;
+ }
+
+ /* Create a heap to hold the shared messages that the list or B-tree will index */
+ /* JAMES: this should happen first, so that the list/btree size can scale depending
+ * on how big a heap pointer is.
+ */
+ HDmemset(&fheap_cparam, 0, sizeof(fheap_cparam));
+ fheap_cparam.managed.width = H5SM_FHEAP_MAN_WIDTH;
+ fheap_cparam.managed.start_block_size = H5SM_FHEAP_MAN_START_BLOCK_SIZE;
+ fheap_cparam.managed.max_direct_size = H5SM_FHEAP_MAN_MAX_DIRECT_SIZE;
+ fheap_cparam.managed.max_index = H5SM_FHEAP_MAN_MAX_INDEX;
+ fheap_cparam.managed.start_root_rows = H5SM_FHEAP_MAN_START_ROOT_ROWS;
+ fheap_cparam.checksum_dblocks = H5SM_FHEAP_CHECKSUM_DBLOCKS;
+ fheap_cparam.id_len = 0;
+ fheap_cparam.max_man_size = H5SM_FHEAP_MAX_MAN_SIZE;
+ if(NULL == (fheap = H5HF_create(f, dxpl_id, &fheap_cparam)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "unable to create fractal heap")
+
+ if(H5HF_get_heap_addr(fheap, &(header->heap_addr )) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGETSIZE, FAIL, "can't get fractal heap address")
+
+ if(H5HF_get_id_len(fheap, &fheap_id_len) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGETSIZE, FAIL, "can't get fractal heap ID length")
+
+done:
+ /* Close the fractal heap if one has been created */
+ if(fheap)
+ if(H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_create_index */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_create_list
+ *
+ * Purpose: Creates a list of SOHM messages.
+ *
+ * Called when a new index is created from scratch or when a
+ * B-tree needs to be converted back into a list.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, August 28, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5SM_create_list(H5F_t *f, H5SM_index_header_t * header, hid_t dxpl_id)
+{
+ H5SM_list_t *list = NULL; /* List of messages */
+ hsize_t x; /* Counter variable */
+ hsize_t size; /* Size of list on disk */
+ size_t num_entries; /* Number of messages to create in list */
+ haddr_t addr = HADDR_UNDEF; /* Address of the list on disk */
+ haddr_t ret_value;
+
+ FUNC_ENTER_NOAPI(H5SM_create_list, HADDR_UNDEF)
+
+ HDassert(f);
+ HDassert(header);
+
+ num_entries = header->list_to_btree;
+
+ /* Allocate list in memory */
+ if((list = H5FL_MALLOC(H5SM_list_t)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for SOHM list")
+ if((list->messages = H5FL_ARR_MALLOC(H5SM_sohm_t, num_entries)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for SOHM list")
+
+ /* Initialize list */
+ /* JAMES: would making fewer operations out of this make it faster? */
+ for(x=0; x<num_entries; x++)
+ {
+ list->messages[x].fheap_id=0;
+ list->messages[x].hash=H5O_HASH_UNDEF;
+ }
+
+ list->header = header;
+
+ /* Allocate space for the list on disk */
+ size = H5SM_LIST_SIZE(f, num_entries);
+ if(HADDR_UNDEF == (addr = H5MF_alloc(f, H5FD_MEM_SOHM, dxpl_id, size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, "file allocation failed for SOHM list")
+
+ /* Put the list into the cache */
+ if(H5AC_set(f, dxpl_id, H5AC_SOHM_LIST, addr, list, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, HADDR_UNDEF, "can't add SOHM list to cache")
+
+ ret_value = addr;
+done:
+ if(ret_value == HADDR_UNDEF)
+ {
+ if(list != NULL)
+ {
+ if(list->messages != NULL)
+ H5FL_ARR_FREE(H5SM_sohm_t, list->messages);
+ H5FL_FREE(H5SM_list_t, list);
+
+ }
+ if(addr != HADDR_UNDEF)
+ {
+ H5MF_xfree(f, H5FD_MEM_SOHM, dxpl_id, addr, size);
+ }
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_create_list */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_try_share
+ *
+ * Purpose: Attempts to share an object header message. If the message
+ * should be shared (if sharing has been enabled and this
+ * message qualified), turns the message into a shared message.
+ *
+ * If not, returns FALSE and does nothing.
+ *
+ * If this message was already shared, increments its reference
+ * count and leaves it otherwise unchanged.
+ *
+ * Return: TRUE if message is now a SOHM
+ * FALSE if this message is not a SOHM
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5SM_try_share(H5F_t *f, hid_t dxpl_id, unsigned type_id, void *mesg)
+{
+ size_t mesg_size;
+ htri_t tri_ret;
+ H5SM_master_table_t *table = NULL;
+ unsigned cache_flags = H5AC__NO_FLAGS_SET;
+ ssize_t index_num;
+ herr_t ret_value = SUCCEED;
+ FUNC_ENTER_NOAPI(H5SM_try_share, FAIL)
+
+ /* Check whether this message ought to be shared or not */
+ /* If sharing is disabled in this file, don't share the message */
+ if(f->shared->sohm_addr == HADDR_UNDEF)
+ HGOTO_DONE(FALSE);
+
+ /* If the message isn't big enough, don't bother sharing it */
+ if((mesg_size = H5O_mesg_size(type_id, f, mesg, 0)) <0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unable to get OH message size")
+ if(mesg_size < 15) /* JAMES: arbitrary value. Make this per-index, along with index sizes? */
+ HGOTO_DONE(FALSE);
+
+ /* JAMES_HEAP: skip this step if it's already shared--just increment the refcount on the message itself */
+
+ /* Type-specific checks */
+ /* JAMES: should this go here? Should there be a "can share" callback? */
+ if(type_id == H5O_DTYPE_ID)
+ {
+ /* Don't share immutable datatypes */
+ if((tri_ret = H5T_is_immutable((H5T_t*) mesg)) > 0)
+ {
+ HGOTO_DONE(FALSE);
+ }
+ else if(tri_ret <0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "can't tell if datatype is immutable")
+ /* Don't share committed datatypes */
+ if((tri_ret = H5T_committed((H5T_t*) mesg)) > 0)
+ {
+ HGOTO_DONE(FALSE);
+ }
+ else if(tri_ret <0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "can't tell if datatype is comitted")
+ }
+
+ /* Look up the master SOHM table */
+ if (NULL == (table = H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, f->shared->sohm_addr, NULL, NULL, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Find the right index for this message type. If there is no such index
+ * then this type of message isn't shareable
+ */
+ H5E_BEGIN_TRY {
+ index_num = H5SM_get_index(table, type_id);
+ } H5E_END_TRY
+ if(index_num < 0)
+ HGOTO_DONE(FALSE);
+
+ /* At this point, the message should definitely be shared. */
+
+ /* If the index hasn't been allocated yet, create it */
+ if(table->indexes[index_num].index_addr == HADDR_UNDEF)
+ {
+ if(H5SM_create_index(f, &(table->indexes[index_num]), dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINIT, FAIL, "unable to create SOHM index")
+ cache_flags |= H5AC__DIRTIED_FLAG;
+ }
+
+ /* Write the message as a shared message */
+ if(H5SM_write_mesg(f, dxpl_id, &(table->indexes[index_num]), type_id, mesg, &cache_flags) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTINSERT, FAIL, "can't write shared message")
+
+done:
+ /* Release the master SOHM table */
+ if (table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, f->shared->sohm_addr, table, cache_flags) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTRELEASE, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_write_mesg
+ *
+ * Purpose: Writes a message to an existing index and change the message
+ * to reflect that it's now shared.
+ *
+ * If the message is already in the index, increment its
+ * reference count instead of writing it again and make the
+ * user's copy point to the copy we wrote before.
+ *
+ * The index could be a list or a B-tree.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_write_mesg(H5F_t *f, hid_t dxpl_id, H5SM_index_header_t *header,
+ unsigned type_id, void *mesg, unsigned *cache_flags_ptr)
+{
+ H5SM_list_t *list = NULL; /* List index */
+ H5SM_mesg_key_t key; /* Key used to search the index */
+ H5O_shared_t shared; /* Shared H5O message */
+ hsize_t list_pos; /* Position in a list index */
+ hbool_t found = FALSE; /* Was the message in the index? */
+ H5HF_t *fheap = NULL; /* Fractal heap handle */
+ size_t buf_size; /* Size of the encoded message */
+ void * encoding_buf=NULL; /* Buffer for encoded message */
+ herr_t ret_value = SUCCEED;
+ FUNC_ENTER_NOAPI(H5SM_write_mesg, FAIL)
+
+ HDassert(cache_flags_ptr);
+ HDassert(header);
+ HDassert(header->index_type != H5SM_BADTYPE);
+
+ /* Set up a shared message so that we can make this message shared once it's
+ * written to the index. This message is always stored to the heap, not to
+ * an object header.
+ */
+ shared.flags = H5O_SHARED_IN_HEAP_FLAG;
+
+ /* Encode the message to be written */
+ if((buf_size = H5O_raw_size(type_id, f, mesg)) <= 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADSIZE, FAIL, "can't find message size");
+
+ if(NULL == (encoding_buf = H5MM_calloc(buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate buffer for encoding");
+
+ if(H5O_encode(f, encoding_buf, mesg, type_id) < 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "can't encode message to be shared");
+
+ /* Open the fractal heap for this index */
+ if(NULL == (fheap=H5HF_open(f, dxpl_id, header->heap_addr)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* Set up a key for the message to be written */
+ key.hash = H5_checksum_lookup3(encoding_buf, buf_size, type_id);
+ key.encoding = encoding_buf;
+ key.encoding_size = buf_size;
+ key.fheap = fheap;
+ key.mesg_heap_id = -1; /* Message doesn't yet have a heap ID */
+
+ /* Assume the message is already in the index and try to increment its
+ * reference count. If this fails, the message isn't in the index after
+ * all and we'll need to add it.
+ */
+ if(header->index_type == H5SM_LIST)
+ {
+ /* The index is a list; get it from the cache */
+ if (NULL == (list = H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, NULL, header, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
+
+ /* JAMES: not very effecient (gets hash value twice, searches list twice). Refactor. */
+ /* See if the message is already in the index and get its location */
+ /* JAMES: should return a pointer to the message */
+ list_pos=H5SM_find_in_list(f, list, &key);
+ if(list_pos != FAIL)
+ {
+ /* The message was in the index. Increment its reference count. */
+ ++(list->messages[list_pos].ref_count);
+
+ /* Set up the shared location to point to the shared location */
+ shared.u.heap_id = list->messages[list_pos].fheap_id;
+ found = TRUE;
+ }
+ }
+ else /* Index is a B-tree */
+ {
+ HDassert(header->index_type == H5SM_BTREE);
+
+ /* If this returns failure, it means that the message wasn't found. */
+ /* If it succeeds, the heap_id in the shared struct will be set */
+ if(H5B2_modify(f, dxpl_id, H5SM_INDEX, header->index_addr, &key, H5SM_incr_ref, &shared.u.heap_id) >= 0)
+ {
+ found = TRUE;
+ }
+ }
+
+ /* If the message isn't in the list, add it */
+ if(!found)
+ {
+ hsize_t x; /* Counter variable */
+ size_t mesg_size; /* Size of the message on disk */
+
+ /* JAMES: wrap this in a function call? */
+
+ /* Encode the message and get its size */
+ if((mesg_size = H5O_raw_size(type_id, f, mesg)) == 0)
+ HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unable to get size of message")
+
+ if(H5HF_insert(fheap, dxpl_id, mesg_size, key.encoding, &(shared.u.heap_id)) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTINSERT, FAIL, "unable to insert message into fractal heap")
+
+ /* JAMES: this is where we should check for conversion to B-tree. */
+
+ /* JAMES: should be H5SM_insert or something */
+ /* Find an empty spot in the list for the message JAMES: combine this with the previous traversal */
+ /* Insert the new message into the SOHM index */
+ if(header->index_type == H5SM_LIST)
+ {
+ for(x=0; x<header->list_to_btree; x++)
+ {
+ if(list->messages[x].hash == H5O_HASH_UNDEF) /* JAMES: is this a valid test? */
+ {
+ list->messages[x].fheap_id = shared.u.heap_id;
+ list->messages[x].hash = key.hash;
+ list->messages[x].ref_count = 1;
+ break;
+ }
+ }
+ }
+ else /* Index is a B-tree */
+ {
+ H5SM_sohm_t message;
+ HDassert(header->index_type == H5SM_BTREE);
+ message.fheap_id = shared.u.heap_id;
+ message.hash = key.hash;
+ message.ref_count = 1;
+
+ if(H5B2_insert(f, dxpl_id, H5SM_INDEX, header->index_addr, &message) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "couldn't add SOHM to B-tree")
+ }
+
+ ++(header->num_messages);
+ (*cache_flags_ptr) |= H5AC__DIRTIED_FLAG;
+ }
+
+ /* Change the original message passed in to reflect that it's now shared */
+ if(H5O_set_share(f, dxpl_id, &shared, type_id, mesg) < 0)
+ HGOTO_ERROR (H5E_OHDR, H5E_BADMESG, FAIL, "unable to set sharing information")
+
+done:
+ /* Release the fractal heap if we opened it */
+ if(fheap)
+ if(H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+
+ /* If we got a list out of the cache, release it (it is always dirty after writing a message) */
+ if(list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DIRTIED_FLAG) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
+
+ if(encoding_buf)
+ H5MM_free(encoding_buf);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_try_delete
+ *
+ * Purpose: Given an object header message that is being deleted,
+ * checks if it is a SOHM. If so, decrements its reference
+ * count.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5SM_try_delete(H5F_t *f, hid_t dxpl_id, unsigned type_id, const H5O_shared_t *mesg)
+{
+ H5SM_master_table_t *table = NULL;
+ unsigned cache_flags = H5AC__NO_FLAGS_SET;
+ ssize_t index_num;
+ herr_t ret_value = SUCCEED;
+ FUNC_ENTER_NOAPI(H5SM_try_delete, FAIL)
+
+ HDassert(f);
+ HDassert(mesg);
+
+ /* Make sure SHARED_IN_HEAP flag is set; if not, there's no message to delete */
+ if(0 == (mesg->flags & H5O_SHARED_IN_HEAP_FLAG))
+ HGOTO_DONE(SUCCEED);
+
+ HDassert(f->shared->sohm_addr != HADDR_UNDEF);
+
+ /* Look up the master SOHM table */
+ if (NULL == (table = H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, f->shared->sohm_addr, NULL, NULL, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Find the correct index and try to delete from it */
+ if((index_num = H5SM_get_index(table, type_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, HADDR_UNDEF, "unable to find correct SOHM index")
+
+ /* JAMES: this triggers some warning on heping. "overflow in implicit constant conversion" */
+ if(H5SM_delete_from_index(f, dxpl_id, &(table->indexes[index_num]), type_id, mesg, &cache_flags) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTDELETE, FAIL, "unable to delete mesage from SOHM index")
+
+done:
+ /* Release the master SOHM table */
+ if (table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, f->shared->sohm_addr, table, cache_flags) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_CANTRELEASE, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_find_in_list
+ *
+ * Purpose: Find a message's location in a list
+ *
+ * Return: Number of messages remaining in the index on success
+ * FAIL if message couldn't be found
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5SM_find_in_list(H5F_t *f, H5SM_list_t *list, const H5SM_mesg_key_t *key)
+{
+ hsize_t x;
+ hsize_t ret_value = FAIL;
+ FUNC_ENTER_NOAPI_NOFUNC(H5SM_find_in_list)
+
+ HDassert(f);
+ HDassert(list);
+ HDassert(key);
+
+ for(x=0; x<list->header->list_to_btree; x++)
+ {
+ if(0 == H5SM_message_compare(key, &(list->messages[x])))
+ {
+ ret_value = x;
+ break;
+ }
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5SM_find_in_list */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_delete_from_index
+ *
+ * Purpose: Given a SOHM message, delete it from this index.
+ * JAMES: is the message necessarily in the index? Also, name this "dec ref count" or something.
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, May 2, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5SM_delete_from_index(H5F_t *f, hid_t dxpl_id, H5SM_index_header_t *header, unsigned type_id, const H5O_shared_t * mesg, unsigned *cache_flags)
+{
+ H5SM_list_t *list = NULL;
+ H5SM_mesg_key_t key;
+ H5SM_sohm_t message;
+ unsigned char *buf = NULL;
+ size_t buf_size;
+ hsize_t list_pos; /* Position of the message in the list */
+ H5HF_t *fheap=NULL; /* Fractal heap that contains the message */
+ herr_t ret_value = SUCCEED;
+ FUNC_ENTER_NOAPI(H5SM_delete_from_index, FAIL)
+
+ HDassert(header);
+ HDassert(mesg);
+ HDassert(cache_flags);
+ HDassert(mesg->flags & H5O_SHARED_IN_HEAP_FLAG);
+
+
+ /* Open the heap that this message is in */
+ if(NULL == (fheap=H5HF_open(f, dxpl_id, header->heap_addr)))
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTOPENOBJ, FAIL, "unable to open fractal heap")
+
+ /* JAMES: use heap op command */
+ /* Get the message size */
+ if(H5HF_get_obj_len(fheap, dxpl_id, &(mesg->u.heap_id), &buf_size) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't get message size from fractal heap.")
+
+ /* Allocate a buffer to hold the message */
+ if(NULL == (buf = HDmalloc(buf_size)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "couldn't allocate memory");
+
+ /* Read the message to get its hash value */
+ if(H5HF_read(fheap, dxpl_id, &(mesg->u.heap_id), buf) < 0)
+ HGOTO_ERROR(H5E_HEAP, H5E_CANTGET, FAIL, "can't read message from fractal heap.")
+
+
+ /* Set up key for message to be deleted. */
+ key.hash = H5_checksum_lookup3(buf, buf_size, type_id);
+ key.encoding = NULL;
+ key.encoding_size = 0;
+ key.fheap = fheap; /* JAMES: unused */
+ key.mesg_heap_id = mesg->u.heap_id;
+
+ /* Try to find the message in the index */
+ if(header->index_type == H5SM_LIST)
+ {
+ /* If the index is stored as a list, get it from the cache */
+ if (NULL == (list = H5AC_protect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, NULL, header, H5AC_WRITE)))
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTPROTECT, FAIL, "unable to load SOHM index")
+
+ /* Find the message in the list */
+ if((list_pos = H5SM_find_in_list(f, list, &key)) == FAIL)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
+
+ --(list->messages[list_pos].ref_count);
+ /* Copy the message */
+ message = list->messages[list_pos];
+ }
+ else /* Index is a B-tree */
+ {
+ HDassert(header->index_type == H5SM_BTREE);
+
+ /* If this returns failure, it means that the message wasn't found.
+ * If it succeeds, a copy of the modified message will be returned. */
+ if(H5B2_modify(f, dxpl_id, H5SM_INDEX, header->index_addr, &key, H5SM_decr_ref, &message) <0)
+ HGOTO_ERROR(H5E_SOHM, H5E_NOTFOUND, FAIL, "message not in index")
+ }
+
+ /* If the ref count is zero, delete the message from the index */
+ if(message.ref_count <= 0)
+ {
+ /* Remove the message from the heap */
+ if(H5HF_remove(fheap, dxpl_id, &(message.fheap_id)) < 0)
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTREMOVE, FAIL, "unable to remove message from heap")
+
+ if(header->index_type == H5SM_LIST)
+ {
+ list->messages[list_pos].hash = H5O_HASH_UNDEF;
+ }
+ else
+ {
+ if(H5B2_remove(f, dxpl_id, H5SM_INDEX, header->index_addr, &key, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_BTREE, H5E_CANTREMOVE, FAIL, "unable to delete message")
+ }
+
+ /* Update the index header, so set its dirty flag */
+ --header->num_messages;
+ *cache_flags |= H5AC__DIRTIED_FLAG;
+ }
+
+done:
+ /* Free the message buffer */
+ if(buf)
+ HDfree(buf);
+
+ /* Release the SOHM list */
+ if (list && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_LIST, header->index_addr, list, H5AC__DIRTIED_FLAG) < 0)
+ HDONE_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "unable to close SOHM index")
+
+ /* Release the fractal heap if we opened it */
+ if(fheap)
+ if(H5HF_close(fheap, dxpl_id) < 0)
+ HDONE_ERROR(H5E_HEAP, H5E_CLOSEERROR, FAIL, "can't close fractal heap")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5SM_get_info
+ *
+ * Purpose: Get the list-to-btree and btree-to-list cutoff numbers for
+ * an index within the master table.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Thursday, May 11, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t H5SM_get_info(H5F_t *f, haddr_t table_addr, unsigned *nindexes,
+ unsigned *index_flags, size_t *list_to_btree,
+ size_t *btree_to_list, hid_t dxpl_id)
+{
+ H5SM_master_table_t *table = NULL;
+ unsigned i;
+ herr_t ret_value = SUCCEED;
+ FUNC_ENTER_NOAPI(H5SM_get_info, FAIL)
+
+ HDassert(table_addr != HADDR_UNDEF);
+
+ /* Get the SOHM table from the cache */
+ if (NULL == (table = H5AC_protect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, NULL, NULL, H5AC_READ)))
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, FAIL, "unable to load SOHM master table")
+
+ /* Return info */
+ *nindexes = table->num_indexes;
+ *list_to_btree = table->indexes[0].list_to_btree;
+ *btree_to_list = table->indexes[0].btree_to_list;
+
+ /* Get information about the individual SOHM indexes */
+ for(i=0; i<table->num_indexes; ++i)
+ {
+ index_flags[i] = table->indexes[i].mesg_types;
+ }
+
+done:
+ /* Release the master SOHM table if we took it out of the cache */
+ if (table && H5AC_unprotect(f, dxpl_id, H5AC_SOHM_TABLE, table_addr, table, H5AC__NO_FLAGS_SET) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTRELEASE, FAIL, "unable to close SOHM master table")
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+