diff options
author | James Laird <jlaird@hdfgroup.org> | 2006-11-13 20:41:36 (GMT) |
---|---|---|
committer | James Laird <jlaird@hdfgroup.org> | 2006-11-13 20:41:36 (GMT) |
commit | b6c317f27cd150aa7bfc4e9cf275629570c9a319 (patch) | |
tree | 3413a54aec3bbebb821088a473f6ff425c3d39be /src/H5SM.c | |
parent | 77c265f26746359cf348437702c93c162f7022f6 (diff) | |
download | hdf5-b6c317f27cd150aa7bfc4e9cf275629570c9a319.zip hdf5-b6c317f27cd150aa7bfc4e9cf275629570c9a319.tar.gz hdf5-b6c317f27cd150aa7bfc4e9cf275629570c9a319.tar.bz2 |
[svn-r12902] Checkin of Shared Object Header Message work.
This feature is still in progress; Shared Object Header Messages are not
complete as a feature and are not thoroughly tested. There are still
"TODO" comments in the code (comments with the word "JAMES" in them,
so as not to be confused with other TODO comments).
Hopefully this checkin will reduce the liklihood of conflicts as I finish
implementing this feature.
All current tests pass on juniper, copper (parallel), heping, kagiso, and mir.
Diffstat (limited to 'src/H5SM.c')
-rwxr-xr-x | src/H5SM.c | 997 |
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) +} + |