From 79f0efa9fd9c6f81be29a6401d337da817c2f54a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 23 Oct 2002 14:30:50 -0500 Subject: [svn-r6025] Purpose: Feature Add Description: New files for the Flexible Parallel HDF5 stuff. H5FP.c - Module housing the APIs to FPHDF5 H5FPclient.c - Module housing the internal client APIs H5FPserver.c - Module housing the internal server APIs H5FPpublic.h - Header for public APIs H5FPprivate.h - Header for private APIs H5Ofphdf5.c - Way of serializing FPHDF5 information to and from the SAP H5Oplist.c - Way of serializing a generic property list. Solution: [details about the changes, algorithm, etc...] [Please as detail as you can since your own explanation is better than others guessing it from the code.] Platforms tested: Tested h5committest {arabica (fortran), eirene (fortran, C++) modi4 (parallel, fortran)}? [If no, why not?] Other platforms/configurations tested? Misc. update: Update MANIFEST if you add or remove any file. Update release_docs/RELEASE for bug fixes, new features, etc. Update applicable document files too. --- src/H5FP.c | 284 +++++++++++ src/H5FPclient.c | 501 ++++++++++++++++++++ src/H5FPprivate.h | 201 ++++++++ src/H5FPpublic.h | 22 + src/H5FPserver.c | 1358 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/H5Ofphdf5.c | 519 ++++++++++++++++++++ src/H5Oplist.c | 584 +++++++++++++++++++++++ src/H5Oprivate.h | 52 +- 8 files changed, 3516 insertions(+), 5 deletions(-) create mode 100644 src/H5FP.c create mode 100644 src/H5FPclient.c create mode 100644 src/H5FPprivate.h create mode 100644 src/H5FPpublic.h create mode 100644 src/H5FPserver.c create mode 100644 src/H5Ofphdf5.c create mode 100644 src/H5Oplist.c diff --git a/src/H5FP.c b/src/H5FP.c new file mode 100644 index 0000000..5144119 --- /dev/null +++ b/src/H5FP.c @@ -0,0 +1,284 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include +#include +#include + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error Handling */ +#include "H5FPprivate.h" /* Flexible Parallel Functions */ +#include "H5Oprivate.h" /* Object Headers */ +#include "H5TBprivate.h" /* Threaded, Balanced, Binary Trees */ + +#ifdef H5_HAVE_FPHDF5 + +#include "mpi.h" + +/* Interface initialization */ +#define PABLO_MASK H5FP_mask +#define INTERFACE_INIT NULL + +static int interface_initialize_g = 0; + +MPI_Datatype SAP_request_t; /* MPI datatype for the SAP_request obj */ +MPI_Datatype SAP_reply_t; /* MPI datatype for the SAP_reply obj */ +MPI_Datatype SAP_sync_t; /* MPI datatype for the SAP_sync obj */ + +/* SAP specific variables */ +MPI_Comm H5FP_SAP_COMM; /* Comm we use: Supplied by user */ +MPI_Comm H5FP_SAP_BARRIER_COMM; /* Comm if you want to do a barrier */ + +unsigned H5FP_sap_rank; /* The rank of the SAP: Supplied by user*/ +unsigned H5FP_capt_rank; /* The rank which tells SAP of opens */ +unsigned H5FP_my_rank; /* Rank of this process in the COMM */ +int H5FP_comm_size; /* Size of the COMM */ + +/* local functions */ +static herr_t H5FP_commit_sap_datatypes(void); +static herr_t H5FP_request_sap_stop(void); + +/** API Functions **/ + +/* + * Function: H5FPinit + * Purpose: Initialize the SAP environment: duplicate the COMM the user + * supplies to us, set aside the SAP_RANK as the SAP. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 26. July, 2002 + * Modifications: + */ +herr_t +H5FPinit(MPI_Comm comm, int sap_rank) +{ + MPI_Group sap_group = MPI_GROUP_NULL, sap_barrier_group = MPI_GROUP_NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(H5FPinit, FAIL); + H5TRACE2("e","McIs",comm,sap_rank); + H5FP_sap_rank = sap_rank; + + if (MPI_Comm_dup(comm, &H5FP_SAP_COMM) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Comm_dup failed"); + + if (MPI_Comm_group(H5FP_SAP_COMM, &sap_group) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Comm_group failed"); + + if (MPI_Group_excl(sap_group, 1, (int *)&H5FP_sap_rank, &sap_barrier_group) + != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Comm_group failed"); + + if (MPI_Comm_create(H5FP_SAP_COMM, sap_barrier_group, &H5FP_SAP_BARRIER_COMM) + != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Comm_create failed"); + + if (MPI_Comm_size(H5FP_SAP_COMM, &H5FP_comm_size) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Comm_size failed"); + + /* we assign the process right after the sap_rank as the one which + * will tell the SAP that files have been opened or closed. + * we mod it so that we don't go over the size of the communicator. */ + H5FP_capt_rank = (H5FP_sap_rank + 1) % H5FP_comm_size; + + if (MPI_Comm_rank(H5FP_SAP_COMM, (int *)&H5FP_my_rank) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Comm_rank failed"); + + if (H5FP_commit_sap_datatypes() != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "H5FP_commit_sap_datatypes failed"); + + if (H5FP_my_rank == H5FP_sap_rank) + H5FP_sap_receive_loop(); + +done: + if (sap_group != MPI_GROUP_NULL) + MPI_Group_free(&sap_group); + + if (sap_barrier_group != MPI_GROUP_NULL) + MPI_Group_free(&sap_barrier_group); + + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FPfinalize + * Purpose: Get rid of the initilized environment we setup with H5FPinit. + * Mostly just freeing the duplicated COMM object and committed + * datatypes. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 26. July, 2002 + * Modifications: + */ +herr_t +H5FPfinalize(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(H5FPfinalize, FAIL); + H5TRACE0("e",""); + + if (H5FP_my_rank != H5FP_sap_rank) + if (H5FP_request_sap_stop() < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Error stopping the SAP"); + + if (MPI_Type_free(&SAP_request_t) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Type_free failed"); + + if (MPI_Type_free(&SAP_reply_t) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Type_free failed"); + + if (MPI_Type_free(&SAP_sync_t) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Type_free failed"); + + if (H5FP_SAP_BARRIER_COMM != MPI_COMM_NULL) + /* this comm will be NULL for the SAP */ + if (MPI_Comm_free(&H5FP_SAP_BARRIER_COMM) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Comm_free failed"); + + if (MPI_Comm_free(&H5FP_SAP_COMM) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Comm_free failed"); + +done: + FUNC_LEAVE(ret_value); +} + +/** Public Libarary (non-API) Functions **/ + +/* + * Function: H5FP_send_metadata + * Purpose: Send a string of metadata to a process. + * + * NOTE: You should never call this function directly!! + * There's special setup for sending a string to a processor + * which needs to occur first. The H5FP_request_* and + * H5FP_reply_* functions take care of this for you. + * + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 30. July, 2002 + * Modifications: + */ +herr_t +H5FP_send_metadata(const char *mdata, int len, int rank) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5FP_send_metadata, FAIL); + assert(mdata); + assert(len); + + /* casts the CONST away: Okay */ + if (MPI_Send((void *)mdata, len, MPI_BYTE, rank, H5FP_TAG_METADATA, H5FP_SAP_COMM) + != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Send failed"); + +done: + FUNC_LEAVE(ret_value); +} + +/** Private Functions **/ + +/* + * Function: H5FP_commit_sap_datatypes + * Purpose: Commit the SAP_request_t, SAP_reply_t, and SAP_sync_t + * structure datatypes to MPI. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 26. July, 2002 + * Modifications: + */ +static herr_t +H5FP_commit_sap_datatypes(void) +{ + int block_length[2]; + MPI_Aint displs[2]; + MPI_Datatype old_types[2]; + struct SAP_request req; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5FP_commit_sap_datatypes, FAIL); + + /* Commit the SAP_request_t datatype */ + block_length[0] = 8; + block_length[1] = sizeof(req.oid); + MPI_Address(&req.req_type, &displs[0]); + MPI_Address(&req.oid, &displs[1]); + displs[1] -= displs[0]; + displs[0] -= displs[0]; + old_types[0] = MPI_INT; + old_types[1] = MPI_UNSIGNED_CHAR; + + if (MPI_Type_struct(2, block_length, displs, old_types, &SAP_request_t) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Type_struct failed"); + + if (MPI_Type_commit(&SAP_request_t) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Type_commit failed"); + + /* Commit the SAP_reply_t datatype */ + block_length[0] = 3; + displs[0] = 0; + old_types[0] = MPI_INT; + + if (MPI_Type_struct(1, block_length, displs, old_types, &SAP_reply_t) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Type_struct failed"); + + if (MPI_Type_commit(&SAP_reply_t) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Type_commit failed"); + + /* Commit the SAP_sync_t datatype */ + block_length[0] = 8; + displs[0] = 0; + old_types[0] = MPI_INT; + + if (MPI_Type_struct(1, block_length, displs, old_types, &SAP_sync_t) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Type_struct failed"); + + if (MPI_Type_commit(&SAP_sync_t) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Type_commit failed"); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_request_sap_stop + * Purpose: Request that the SAP stop it's loop processing. Each + * process should send this to the SAP. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 02. August, 2002 + * Modifications: + */ +static herr_t +H5FP_request_sap_stop(void) +{ + struct SAP_request req; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5FP_request_sap_stop, FAIL); + + HDmemset(&req, 0, sizeof(req)); + req.req_type = H5FP_REQ_STOP; + req.req_id = 0; + req.proc_rank = H5FP_my_rank; + + if (MPI_Send(&req, 1, SAP_request_t, (int)H5FP_sap_rank, + H5FP_TAG_REQUEST, H5FP_SAP_COMM) != MPI_SUCCESS) + HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "MPI_Send failed"); + +done: + FUNC_LEAVE(ret_value); +} + +#endif /* H5_HAVE_FPHDF5 */ diff --git a/src/H5FPclient.c b/src/H5FPclient.c new file mode 100644 index 0000000..366b22f --- /dev/null +++ b/src/H5FPclient.c @@ -0,0 +1,501 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include +#include +#include + +#define H5S_PACKAGE /*suppress error about including H5Spkg */ + +#include "H5Spkg.h" + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error Handling */ +#include "H5FPprivate.h" /* Flexible Parallel Functions */ +#include "H5Oprivate.h" /* Object Headers */ +#include "H5TBprivate.h" /* Threaded, Balanced, Binary Trees */ + +#ifdef H5_HAVE_FPHDF5 + +#include "mpi.h" + +/* Pablo mask */ +#define PABLO_MASK H5FPclient_mask + +/* Is the interface initialized? */ +static int interface_initialize_g = 0; + +#define INTERFACE_INIT NULL + +MPI_Datatype SAP_request_t; /* MPI datatype for the SAP_request obj */ +MPI_Datatype SAP_reply_t; /* MPI datatype for the SAP_reply obj */ +MPI_Datatype SAP_sync_t; /* MPI datatype for the SAP_sync obj */ + +/* SAP specific variables */ +MPI_Comm H5FP_SAP_COMM; /* Comm we use: Supplied by user */ +MPI_Comm H5FP_SAP_BARRIER_COMM; /* Comm if you want to do a barrier */ + +unsigned H5FP_sap_rank; /* The rank of the SAP: Supplied by user*/ +unsigned H5FP_my_rank; /* Rank of this process in the COMM */ +int H5FP_comm_size; /* Size of the COMM */ + +/* local functions */ +static unsigned int H5FP_gen_request_id(void); +static herr_t H5FP_update_metadata_cache(hid_t file_id, struct SAP_sync *sap_sync, + H5O_fphdf5_t *fmeta); + +/** Public Library (non-API) Functions **/ + +/* + * Function: H5FP_request_open + * Purpose: Request an open of an object from the SAP. You pass in + * the metadata string (MDATA) (this is normally the + * filename or pathname to the object), it's length in + * (MD_LEN), and the type of the object you're trying to + * open (OBJ_TYPE). The request ID is returned in a pointer + * supplied by the user. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 28. August, 2002 + * Modifications: + */ +herr_t +H5FP_request_open(const char *mdata, int md_len, enum sap_obj_type obj_type, + unsigned *file_id, unsigned *req_id) +{ + struct SAP_request req; + MPI_Status mpi_status; + int ret_value = SUCCEED, mrc; + + FUNC_ENTER_NOAPI(H5FP_request_open, FAIL); + + assert(mdata); + assert(file_id); + assert(req_id); + HDmemset(&mpi_status, 0, sizeof(MPI_Status)); + + if (H5FP_my_rank == H5FP_capt_rank) { + HDmemset(&req, 0, sizeof(req)); + req.req_type = H5FP_REQ_OPEN; + req.req_id = H5FP_gen_request_id(); + req.proc_rank = H5FP_my_rank; + req.md_len = md_len; + req.obj_type = obj_type; + + if ((mrc = MPI_Send(&req, 1, SAP_request_t, (int)H5FP_sap_rank, + H5FP_TAG_REQUEST, H5FP_SAP_COMM)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + /* The first MPI_Send will have been sent before this one will be read. */ + + if (H5FP_send_metadata(mdata, md_len, (int)H5FP_sap_rank)) + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTSENDMDATA, FAIL, "can't send metadata to server"); + } + + if ((mrc = MPI_Recv(file_id, 1, MPI_UNSIGNED, (int)H5FP_sap_rank, + H5FP_TAG_FILE_ID, H5FP_SAP_COMM, &mpi_status)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + printf("%u: New File ID == %u\n", H5FP_my_rank, *file_id); + fflush(stdout); + +done: + *req_id = req.req_id; + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_request_lock + * Purpose: Request a lock on an object in a file from the SAP. The + * request ID is returned in a pointer supplied by the user. + * The status of the SAP is returned to the user in the + * supplied STATUS pointer. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 30. July, 2002 + * Modifications: + */ +herr_t +H5FP_request_lock(unsigned int sap_file_id, unsigned char *obj_oid, + enum sap_lock_type rw_lock, int last, unsigned *req_id, + enum sap_status *status) +{ + struct SAP_request req; + int ret_value = SUCCEED, mrc; + + FUNC_ENTER_NOAPI(H5FP_request_lock, FAIL); + + assert(obj_oid); + assert(req_id); + assert(status); + HDmemset(&req, 0, sizeof(req)); + + *status = H5FP_STATUS_OK; + req.req_type = last ? H5FP_REQ_LOCK_END : H5FP_REQ_LOCK; + req.req_id = H5FP_gen_request_id(); + req.sap_file_id = sap_file_id; + req.rw_lock = rw_lock; + req.md_len = 0; + req.proc_rank = H5FP_my_rank; + H5FP_COPY_OID(req.oid, obj_oid); + + if ((mrc = MPI_Send(&req, 1, SAP_request_t, (int)H5FP_sap_rank, + H5FP_TAG_REQUEST, H5FP_SAP_COMM)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + if (last) { + /* + * On the last lock in the lock-group to be acquired, we expect a + * reply from the SAP + */ + struct SAP_reply sap_reply; + MPI_Status mpi_status; + + HDmemset(&mpi_status, 0, sizeof(mpi_status)); + + if ((mrc = MPI_Recv(&sap_reply, 1, SAP_reply_t, (int)H5FP_sap_rank, + H5FP_TAG_REPLY, H5FP_SAP_COMM, &mpi_status)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Recv failed", mrc); + + *status = sap_reply.status; + + if (sap_reply.status != H5FP_STATUS_LOCK_ACQUIRED) + HGOTO_DONE(FAIL); + } + +done: + *req_id = req.req_id; + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_request_release_lock + * Purpose: Release a lock on the file from the SAP. Request a lock + * on an object in a file from the SAP. The request ID is + * returned in a pointer supplied by the user. The status + * of the SAP is returned to the user in the supplied STATUS + * pointer. + * Return: Success: The request ID. + * Failure: -1 + * Programmer: Bill Wendling, 30. July, 2002 + * Modifications: + */ +herr_t +H5FP_request_release_lock(unsigned int sap_file_id, unsigned char *obj_oid, + int last, unsigned *req_id, enum sap_status *status) +{ + struct SAP_request req; + herr_t ret_value = SUCCEED; + int mrc; + + FUNC_ENTER_NOAPI(H5FP_request_release_lock, FAIL); + + assert(req_id); + assert(status); + + HDmemset(&req, 0, sizeof(req)); + + *status = H5FP_STATUS_OK; + req.req_type = last ? H5FP_REQ_RELEASE_END : H5FP_REQ_RELEASE; + req.req_id = H5FP_gen_request_id(); + req.sap_file_id = sap_file_id; + req.md_len = 0; + req.proc_rank = H5FP_my_rank; + + if (obj_oid) + H5FP_COPY_OID(req.oid, obj_oid); + else + HDmemset(req.oid, '\0', sizeof(req.oid)); + + if ((mrc = MPI_Send(&req, 1, SAP_request_t, (int)H5FP_sap_rank, + H5FP_TAG_REQUEST, H5FP_SAP_COMM)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + if (last) { + /* + * On the last lock released in this lock-group, we expect a + * reply from the SAP + */ + struct SAP_reply sap_reply; + MPI_Status mpi_status; + + HDmemset(&mpi_status, 0, sizeof(mpi_status)); + + if ((mrc = MPI_Recv(&sap_reply, 1, SAP_reply_t, (int)H5FP_sap_rank, + H5FP_TAG_REPLY, H5FP_SAP_COMM, &mpi_status)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Recv failed", mrc); + + *status = sap_reply.status; + + if (sap_reply.status != H5FP_STATUS_LOCK_RELEASED) { + HDfprintf(stderr, "Release: For some reason, we couldn't release the lock\n"); + HDfprintf(stderr, "Release: reply status == %d\n", sap_reply.status); + HGOTO_DONE(FAIL); + } + } + +done: + *req_id = req.req_id; + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_request_change + * Purpose: Tell the SAP that we want to change the structure of the file. + * Include the information the SAP will need to send to the + * other processes so that they can be synced with what you + * are doing. The request ID is returned in a pointer + * supplied by the user. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 02. August, 2002 + * Modifications: + */ +herr_t +H5FP_request_change(unsigned int sap_file_id, enum sap_obj_type obj_type, + enum sap_action action, int mdata_len, const char *mdata, + unsigned *req_id) +{ + struct SAP_request req; + herr_t ret_value = SUCCEED; + int mrc; + + FUNC_ENTER_NOAPI(H5FP_request_change, FAIL); + + assert(mdata); + HDmemset(&req, 0, sizeof(req)); + + req.req_type = H5FP_REQ_CHANGE; + req.req_id = H5FP_gen_request_id(); + req.sap_file_id = sap_file_id; + req.obj_type = obj_type; + req.action = action; + req.md_len = mdata_len; + req.proc_rank = H5FP_my_rank; + + if ((mrc = MPI_Send(&req, 1, SAP_request_t, (int)H5FP_sap_rank, + H5FP_TAG_REQUEST, H5FP_SAP_COMM)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + /* The first MPI_Send will have been sent before this one will be read. */ + if (H5FP_send_metadata(mdata, mdata_len, (int)H5FP_sap_rank) != SUCCEED) + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTSENDMDATA, FAIL, "can't send metadata to server"); + +done: + *req_id = req.req_id; + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_request_sync + * Purpose: Tell the SAP that we want all of the structural changes + * made on the file that we don't know about. The request ID + * is returned in a pointer supplied by the user. The status + * of the SAP is returned to the user in the supplied STATUS + * pointer. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 02. August, 2002 + * Modifications: + */ +herr_t +H5FP_request_sync(unsigned int sap_file_id, hid_t hdf_file_id, + unsigned *req_id, enum sap_status *status) +{ + struct SAP_request req; + herr_t ret_value = SUCCEED; + int mrc; + + FUNC_ENTER_NOAPI(H5FP_request_sync, FAIL); + + assert(req_id); + assert(status); + + HDmemset(&req, 0, sizeof(req)); + + *status = H5FP_STATUS_OK; + req.req_type = H5FP_REQ_SYNC; + req.req_id = H5FP_gen_request_id(); + req.sap_file_id = sap_file_id; + req.proc_rank = H5FP_my_rank; + + if ((mrc = MPI_Send(&req, 1, SAP_request_t, (int)H5FP_sap_rank, + H5FP_TAG_REQUEST, H5FP_SAP_COMM)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + for (;;) { + MPI_Status mpi_status; + struct SAP_sync sap_sync; + + HDmemset(&mpi_status, 0, sizeof(mpi_status)); + + if ((mrc = MPI_Recv(&sap_sync, 1, SAP_sync_t, (int)H5FP_sap_rank, H5FP_TAG_SYNC, + H5FP_SAP_COMM, &mpi_status)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Recv failed", mrc); + + if (sap_sync.status != H5FP_STATUS_OK) { + *status = sap_sync.status; + HGOTO_DONE(FAIL); + } + + if (sap_sync.last_msg) + break; + + /* use the info in the SAP_sync_t structure to update the + * metadata */ + if (sap_sync.md_len) { + H5O_fphdf5_t *fmeta; + char *buf; + + if ((buf = (char *)HDcalloc((size_t)sap_sync.md_len + 1, 1)) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "out of memory"); + + HDmemset(&mpi_status, 0, sizeof(mpi_status)); + + if ((mrc = MPI_Recv(buf, sap_sync.md_len, MPI_BYTE, (int)H5FP_sap_rank, + H5FP_TAG_METADATA, H5FP_SAP_COMM, &mpi_status)) != MPI_SUCCESS) { + HDfree(buf); + HMPI_GOTO_ERROR(FAIL, "MPI_Recv failed", mrc); + } + + /* + * FIXME: perform whatever metadata updates we can with the + * metadata returned from the SAP + */ + fmeta = H5O_FPHDF5[0].decode(NULL, buf, NULL); + HDfree(buf); + + if (H5FP_update_metadata_cache(hdf_file_id, &sap_sync, fmeta) != SUCCEED) { + H5O_FPHDF5[0].free(fmeta); + HGOTO_DONE(FAIL); + } + + H5O_FPHDF5[0].free(fmeta); + } + } + +done: + *req_id = req.req_id; + FUNC_LEAVE(ret_value); +} + +#if 0 +struct SAP_sync { + unsigned int req_id; /* Request ID copied from the SAP_request */ + unsigned int sync_id; /* Sync ID to order the sync messages */ + unsigned int sap_file_id; /* SAP's file ID for the specific file */ + unsigned int last_msg; /* Indicates this is the last sync msg sent */ + int md_len; /* Length of the metadata sent in next msg */ + enum sap_obj_type obj_type; /* Type of object */ + enum sap_action action; /* Action done on the object */ + enum sap_status status; /* Status of the request */ +}; + +typedef struct H5O_fphdf5_t { + uint8_t oid[H5R_OBJ_REF_BUF_SIZE]; /* OID of object */ + struct H5S_simple_t *sdim; /* Simple dimensionality structure */ + H5T_t *dtype; /* Datatype structure */ + time_t *mtime; /* Modification time */ + H5O_name_t *group; /* Group name */ + H5O_name_t *dset; /* Dataset name */ + struct H5P_genplist_t *plist; /* Pathname of the object */ +} H5O_fphdf5_t; +#endif + +static herr_t +H5FP_update_metadata_cache(hid_t file_id, struct SAP_sync *sap_sync, H5O_fphdf5_t *fmeta) +{ + herr_t ret_value = SUCCEED; + hid_t gid, dset_id; + + FUNC_ENTER_NOINIT(H5FP_update_metadata_cache); + + /* check args */ + assert(sap_sync); + assert(fmeta); + + switch (sap_sync->action) { + case H5FP_ACT_CREATE: + case H5FP_ACT_EXTEND: + if (sap_sync->obj_type == H5FP_OBJ_DATASET) { + gid = H5Gopen(file_id, fmeta->group->s); + dset_id = H5Dopen(gid, fmeta->dset->s); + + if (H5Dextend(dset_id, fmeta->sdim->size) != SUCCEED) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "metadata update failed"); + } + + break; + case H5FP_ACT_DELETE: + default: + break; + } + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_request_close + * Purpose: Tell the SAP that we want all of the structural changes + * made on the file and then close the file. The request ID + * is returned in a pointer passed to the function by the + * user. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 02. August, 2002 + * Modifications: + */ +herr_t +H5FP_request_close(unsigned sap_file_id, unsigned *req_id) +{ + struct SAP_request req; + int ret_value = SUCCEED, mrc; + + FUNC_ENTER_NOAPI(H5FP_request_close, FAIL); + + HDmemset(&req, 0, sizeof(req)); + req.req_type = H5FP_REQ_CLOSE; + req.req_id = H5FP_gen_request_id(); + req.sap_file_id = sap_file_id; + req.proc_rank = H5FP_my_rank; + + if ((mrc = MPI_Send(&req, 1, SAP_request_t, (int)H5FP_sap_rank, + H5FP_TAG_REQUEST, H5FP_SAP_COMM)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + *req_id = req.req_id; + +done: + FUNC_LEAVE(ret_value); +} + +/** Private Functions **/ + +/* + * Function: H5FP_gen_request_id + * Purpose: Generate a unique request ID to send along with a + * message. + * Return: Integer >= 0 - Doesn't fail. + * Programmer: Bill Wendling, 30. July, 2002 + * Modifications: + */ +static unsigned int H5FP_gen_request_id() +{ + static unsigned int i = 0; + + FUNC_ENTER_NOINIT(H5FP_gen_request_id); + FUNC_LEAVE(i++); +} + +#endif /* H5_HAVE_FPHDF5 */ diff --git a/src/H5FPprivate.h b/src/H5FPprivate.h new file mode 100644 index 0000000..c5e5f00 --- /dev/null +++ b/src/H5FPprivate.h @@ -0,0 +1,201 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#ifndef H5FPPRIVATE_H__ +#define H5FPPRIVATE_H__ 0 + +#include "H5FPpublic.h" /* Flexible Parallel HDF5 */ +#include "H5Rprivate.h" /* References */ + +#ifndef TRUE +#define TRUE 1 +#endif /* !TRUE */ + +#ifndef FALSE +#define FALSE 0 +#endif /* !FALSE */ + +#define H5FP_BYTE_BITS 8 + +/* Different types of requests */ + +/* + * The H5FP_REQ_LOCK_END and H5FP_REQ_RELEASE_END are used to lock and + * release a collection of objects at the same time. The last object you + * need to lock is sent with the H5FP_REQ_LOCK_END request type (this can + * also be a null message - where you're just sending a message that has + * H5FP_REQ_LOCK_END as the request type with no data associated with it. + * In that case, the md_len MUST be set to 0). The SAP will then try to + * lock all of the objects you've requested to lock at once. If it cannot + * do so, then it will fail and you have to try again at a later time. + * + * Releasing locks is done in the exact same way, except that the action + * will always release locks (i.e., not fail) if there is a vaild lock + * for that object. + */ +enum sap_request { + H5FP_REQ_OPEN, + H5FP_REQ_LOCK, + H5FP_REQ_LOCK_END, + H5FP_REQ_RELEASE, + H5FP_REQ_RELEASE_END, + H5FP_REQ_CHANGE, + H5FP_REQ_SYNC, + H5FP_REQ_CLOSE, + H5FP_REQ_STOP +}; + +/* Actions to take when performing a change */ +enum sap_action { + H5FP_ACT_CREATE, + H5FP_ACT_EXTEND, + H5FP_ACT_DELETE +}; + +/* Types of objects we can change */ +enum sap_obj_type { + H5FP_OBJ_FILE, + H5FP_OBJ_GROUP, + H5FP_OBJ_DATASET, + H5FP_OBJ_DATATYPE, + H5FP_OBJ_ATTRIBUTE +}; + +/* Types of locks we can get */ +enum sap_lock_type { + H5FP_LOCK_READ, + H5FP_LOCK_WRITE +}; + +/* The structure sent to the SAP which holds all of the requested action */ +struct SAP_request { + enum sap_request req_type; /* Request type */ + unsigned int req_id; /* ID for request set by sending process */ + unsigned int proc_rank; /* Rank of sending process */ + unsigned int sap_file_id; /* SAP's file ID for the specific file */ + int md_len; /* Length of the metadata sent in next msg */ + enum sap_obj_type obj_type; /* Type of object */ + enum sap_action action; /* Action to do to object (H5FP_REQ_CHANGE only) */ + enum sap_lock_type rw_lock; /* Indicates read or write lock */ + unsigned char oid[H5R_OBJ_REF_BUF_SIZE]; /* Buffer to store OID of object referenced */ +}; + +extern MPI_Datatype SAP_request_t; /* MPI datatype for the SAP_request obj */ + +/* The status of the SAP */ +enum sap_status { + H5FP_STATUS_OK, + + /* For locking */ + H5FP_STATUS_LOCK_ACQUIRED, + H5FP_STATUS_LOCK_FAILED, + + /* For releasing locks */ + H5FP_STATUS_LOCK_RELEASED, + H5FP_STATUS_LOCK_RELEASE_FAILED, + H5FP_STATUS_BAD_LOCK, /* Process doesn't own a lock on the OID */ + + /* For change requests */ + H5FP_STATUS_FILE_CLOSING, + H5FP_STATUS_NO_LOCK, + + /* Out of memory error */ + H5FP_STATUS_OOM, + + /* Bad file ID */ + H5FP_STATUS_BAD_FILE_ID, + + /* Reserved for completely disasterous failures which require an abort */ + H5FP_STATUS_CATASTROPHIC +}; + +/* Reply from the SAP on an SAP_request send */ +struct SAP_reply { + unsigned int req_id; /* Request ID copied from the SAP_request */ + unsigned int sap_file_id; /* File ID assigned to an open file */ + enum sap_status status; /* Status of the request */ +}; + +extern MPI_Datatype SAP_reply_t; /* MPI datatype for the SAP_reply obj */ + +/* The sync message from the SAP on an SAP_request H5FP_REQ_SYNC send */ +struct SAP_sync { + unsigned int req_id; /* Request ID copied from the SAP_request */ + unsigned int sync_id; /* Sync ID to order the sync messages */ + unsigned int sap_file_id; /* SAP's file ID for the specific file */ + unsigned int last_msg; /* Indicates this is the last sync msg sent */ + int md_len; /* Length of the metadata sent in next msg */ + enum sap_obj_type obj_type; /* Type of object */ + enum sap_action action; /* Action done on the object */ + enum sap_status status; /* Status of the request */ +}; + +extern MPI_Datatype SAP_sync_t; /* MPI datatype for the SAP_sync obj */ + +/* + * Special tag numbers for requests, replies, and string passing messages. + * + * Certain actions (Open, Change, and Close) require a pathname to the + * object. This pathname is sent in a separate message and the SAP will + * search for it after getting the appropriate request. + */ +enum { + H5FP_TAG_REQUEST = 37, + H5FP_TAG_REPLY, + H5FP_TAG_SYNC, + H5FP_TAG_METADATA, + H5FP_TAG_FILE_ID +}; + +/* Handy #define for copying OIDs */ +#define H5FP_COPY_OID(dst, src) HDmemcpy((dst), (src), H5R_OBJ_REF_BUF_SIZE) + +/* SAP specific variables */ +extern MPI_Comm H5FP_SAP_COMM; /* Comm we use: Supplied by user */ +extern MPI_Comm H5FP_SAP_BARRIER_COMM; /* Comm if you want to do a barrier */ + +extern unsigned H5FP_sap_rank; /* The rank of the SAP: Supplied by user */ +extern unsigned H5FP_capt_rank; /* The rank which tells SAP of opens */ +extern unsigned H5FP_my_rank; /* Rank of this process in the COMM */ +extern int H5FP_comm_size; /* Size of the COMM */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* NOTE: Don't use this function explicitly!! */ +extern herr_t H5FP_send_metadata(const char *mdata, int len, int rank); + +/* Start the SAP */ +extern herr_t H5FP_sap_receive_loop(void); + +/* Use these functions to communicate with the SAP */ +extern herr_t H5FP_request_open(const char *mdata, int md_len, enum sap_obj_type obj_type, + unsigned *file_id, unsigned *req_id); +extern herr_t H5FP_request_lock(unsigned int sap_file_id, unsigned char *mdata, + enum sap_lock_type rw_lock, int last, unsigned *req_id, + enum sap_status *status); +extern herr_t H5FP_request_release_lock(unsigned int sap_file_id, unsigned char *mdata, + int last, unsigned *req_id, enum sap_status *status); +extern herr_t H5FP_request_change(unsigned int sap_file_id, enum sap_obj_type obj_type, + enum sap_action action, int mdata_len, const char *mdata, + unsigned *req_id); +extern herr_t H5FP_request_sync(unsigned int sap_file_id, hid_t hdf_file_id, + unsigned *req_id, enum sap_status *status); +extern herr_t H5FP_request_close(unsigned sap_file_id, unsigned *req_id); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* H5FPPRIVATE_H__ */ diff --git a/src/H5FPpublic.h b/src/H5FPpublic.h new file mode 100644 index 0000000..047c0ce --- /dev/null +++ b/src/H5FPpublic.h @@ -0,0 +1,22 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#ifndef H5FPPUBLIC_H__ +#define H5FPPUBLIC_H__ 0 + +#include "H5public.h" + +extern herr_t H5FPinit(MPI_Comm comm, int sap_rank); +extern herr_t H5FPfinalize(void); + +#endif /* H5FPPUBLIC_H__ */ diff --git a/src/H5FPserver.c b/src/H5FPserver.c new file mode 100644 index 0000000..aabd9ef --- /dev/null +++ b/src/H5FPserver.c @@ -0,0 +1,1358 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * NOTE! This is NOT thread safe! + * + * NOTE: There will be caveats on call-back functions. + */ + +/* + * Purpose: + * + * This file has all of the code that a server (SAP) would run to + * handle requests from clients. + */ + +#include +#include +#include + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error Handling */ +#include "H5FPprivate.h" /* Flexible Parallel Functions */ +#include "H5Oprivate.h" /* Object Headers */ +#include "H5TBprivate.h" /* Threaded, Balanced, Binary Trees */ + +#ifdef H5_HAVE_FPHDF5 + +#include "mpi.h" + +/* Pablo mask */ +#define PABLO_MASK H5FPserver_mask + +/* Is the interface initialized? */ +static int interface_initialize_g = 0; + +#define INTERFACE_INIT NULL + +MPI_Datatype SAP_request_t; /* MPI datatype for the SAP_request obj */ +MPI_Datatype SAP_reply_t; /* MPI datatype for the SAP_reply obj */ +MPI_Datatype SAP_sync_t; /* MPI datatype for the SAP_sync obj */ + +/* SAP specific variables */ +MPI_Comm H5FP_SAP_COMM; /* Comm we use: Supplied by user */ +MPI_Comm H5FP_SAP_BARRIER_COMM; /* Comm if you want to do a barrier */ + +unsigned H5FP_sap_rank; /* The rank of the SAP: Supplied by user*/ +unsigned H5FP_my_rank; /* Rank of this process in the COMM */ +int H5FP_comm_size; /* Size of the COMM */ + +/* Internal SAP structures */ + +struct sap_obj_lock { + uint8_t oid[H5R_OBJ_REF_BUF_SIZE]; /* Buffer to store OID of object referenced */ + unsigned int owned_rank; /* rank which has the lock */ + enum sap_obj_type obj_type; /* type of object being locked */ + unsigned int ref_count; /* number of times lock was aquired by proc */ + enum sap_lock_type rw_lock; /* indicates if it's a read or write lock */ +}; + +struct sap_file_mod { + unsigned long key; /* key field for insertion into the TBBT */ + unsigned char *procs_notified; /* bitfield of size MPI_Comm_size() */ + /* indicates process was notified of this + * modification - 0 means no, 1 means yes */ + unsigned num_notified; /* counts number of processes notified */ + enum sap_obj_type obj_type; /* type of object */ + enum sap_action action; /* action done to object (H5FP_REQ_CHANGE only) */ + int md_len; /* the length of the metadata array */ + char *metadata; /* encoded metadata about the object */ +}; + +struct sap_file_struct { + unsigned int sap_file_id; /* the file id the SAP keeps per file */ + char *filename; /* the filename - of dubious use */ + int closing; /* we're closing the file - no more changes */ + H5TB_TREE *mod_tree; /* a tree of the modifications done */ + H5TB_TREE *locks; /* a tree of locks on objects in the file */ +}; + +static H5TB_TREE *fs_tree; + +/* + * Note on procs_notified: + * + * We needed a way of indicating that a process has been notified of a + * change. However, we didn't want to waste space, so I implemented an array + * of unsigned characters which would emulate such a thing. The code: + * + * rank >> 3 + * + * is an integer divide by 8. While the code: + * + * rank & 7 + * + * is a mod by 8. (Note that rank should be unsigned at this point). So, the + * code + * + * fm->procs_notified[rank << 3] |= 1 << (rank & 7); + * + * is equivalent to + * + * fm->procs_notified[rank / 8] |= 1 << (rank % 8); + * + * Testing whether a given bit is set or not involves a test like this: + * + * if (mod->procs_notified[rank >> 3] & (1 << (rank & 7))) + * + * Of course, all bytes are 8 bits wide, right? :-) + * + * The following two macros help this be more readable. + */ + +#define SET_PROC_NOTIFIED(arr, rank) \ + (arr->procs_notified[(rank) >> 3] |= (1 << ((rank) & 7)), ++arr->num_notified) +#define IS_PROC_NOTIFIED(arr, rank) \ + (arr->procs_notified[(rank) >> 3] & (1 << ((rank) & 7))) + +/* local functions */ +static herr_t H5FP_sap_receive(struct SAP_request *req, int source, + int tag, char **buf); + + /* local functions to generate unique ids for messages */ +static unsigned int H5FP_gen_sap_file_id(void); + + /* local functions for handling object locks */ +static int H5FP_object_lock_cmp(struct sap_obj_lock *o1, + struct sap_obj_lock *o2, + int cmparg); +static struct sap_obj_lock *H5FP_new_object_lock(const unsigned char *oid, + unsigned int rank, + enum sap_obj_type obj_type, + enum sap_lock_type rw_lock); +static herr_t H5FP_free_object_lock(struct sap_obj_lock *ol); +static struct sap_obj_lock *H5FP_find_object_lock(struct sap_file_struct *fs, + unsigned char *oid); +static herr_t H5FP_remove_object_lock_from_list(struct sap_file_struct *fs, + struct sap_obj_lock *ol); + + /* local file structure handling functions */ +static herr_t H5FP_add_new_file_struct_to_list(unsigned int sap_file_id, char *filename); +static int H5FP_file_struct_cmp(struct sap_file_struct *k1, + struct sap_file_struct *k2, int cmparg); +static struct sap_file_struct *H5FP_new_file_struct_node(unsigned int sap_file_id, + char *filename); +static struct sap_file_struct *H5FP_find_file_struct(unsigned int sap_file_id); +static herr_t H5FP_remove_file_id_from_list(unsigned int sap_file_id); +static herr_t H5FP_free_file_struct_node(struct sap_file_struct *fs); + + /* local file modification structure handling functions */ +static struct sap_file_mod *H5FP_new_file_mod_node(unsigned rank, + enum sap_obj_type obj_type, + enum sap_action action, + int md_len, + char *metadata); +static herr_t H5FP_free_mod_node(struct sap_file_mod *fs); + + /* local request handling functions */ +static herr_t H5FP_sap_handle_open_request(struct SAP_request req, char *mdata, int md_len); +static herr_t H5FP_sap_handle_lock_request(struct SAP_request req); +static herr_t H5FP_sap_handle_release_lock_request(struct SAP_request req); +static herr_t H5FP_sap_handle_change_request(struct SAP_request req, char *mdata, int md_len); +static herr_t H5FP_sap_handle_sync_request(struct SAP_request req); +static herr_t H5FP_sap_handle_close_request(struct SAP_request req); + +/** Public Library (non-API) Functions **/ + +/* + * Function: H5FP_sap_receive_loop + * Purpose: Just receive message after message from the other + * processes and process that message. Return when we + * receive an "H5FP_REQ_STOP" message from all processes in + * H5FP_SAP_COMM. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 05. August, 2002 + * Modifications: + */ +herr_t +H5FP_sap_receive_loop(void) +{ + herr_t ret_value = SUCCEED; + int stop = 0; + + FUNC_ENTER_NOAPI(H5FP_sap_receive_loop, FAIL); + + if ((fs_tree = H5TB_dmake((H5TB_cmp_t)H5FP_file_struct_cmp, + sizeof(struct sap_file_struct), FALSE)) == NULL) + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTMAKETREE, FAIL, "cannot make TBBT tree"); + + for (;;) { + struct SAP_request req; + char *buf = NULL; + herr_t hrc; + + if (H5FP_sap_receive(&req, MPI_ANY_SOURCE, H5FP_TAG_REQUEST, &buf) != SUCCEED) + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTRECV, FAIL, "cannot receive messages"); + + switch (req.req_type) { + case H5FP_REQ_OPEN: + if ((hrc = H5FP_sap_handle_open_request(req, buf, req.md_len)) != SUCCEED) + fprintf(stderr, "Failed on opening file: %d\n", hrc); + + break; + case H5FP_REQ_LOCK: + case H5FP_REQ_LOCK_END: + hrc = H5FP_sap_handle_lock_request(req); + break; + case H5FP_REQ_RELEASE: + case H5FP_REQ_RELEASE_END: + hrc = H5FP_sap_handle_release_lock_request(req); + break; + case H5FP_REQ_CHANGE: + hrc = H5FP_sap_handle_change_request(req, buf, req.md_len); + break; + case H5FP_REQ_SYNC: + hrc = H5FP_sap_handle_sync_request(req); + break; + case H5FP_REQ_CLOSE: + hrc = H5FP_sap_handle_close_request(req); + break; + case H5FP_REQ_STOP: + if (++stop == H5FP_comm_size - 1) + goto done; + + break; + default: + HDfprintf(stderr, + "error: H5FP_sap_receive_loop: invalid request type %d\n", + req.req_type); + } + + if (hrc != SUCCEED) + HDfree(buf); + } + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_sap_receive + * Purpose: Receive a message from SOURCE with the given TAG. The REQ + * object passed in as a pointer is filled by the MPI_Recv + * function. + * Return: Pointer to string passed in, if one was sent. As well as + * the SAP_request object. + * Programmer: Bill Wendling, 17. September, 2002 + * Modifications: + */ +static herr_t +H5FP_sap_receive(struct SAP_request *req, int source, int tag, char **buf) +{ + MPI_Status status; + herr_t ret_value = SUCCEED; + int mrc; + + FUNC_ENTER_NOINIT(H5FP_sap_receive); + + HDmemset(&status, 0, sizeof(status)); + + if ((mrc = MPI_Recv(req, 1, SAP_request_t, source, tag, + H5FP_SAP_COMM, &status)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Recv failed", mrc); + + if (buf && req->md_len) { + if ((*buf = (char *)HDmalloc((size_t)req->md_len + 1)) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "out of memory"); + + HDmemset(*buf, 0, (size_t)req->md_len + 1); + + if ((mrc = MPI_Recv(*buf, req->md_len, MPI_BYTE, (int)req->proc_rank, + H5FP_TAG_METADATA, H5FP_SAP_COMM, &status)) != MPI_SUCCESS) { + HDfree(*buf); + *buf = NULL; + HMPI_GOTO_ERROR(FAIL, "MPI_Recv failed", mrc); + } + } + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_object_lock_cmp + * Purpose: Comparison function for the TBBT. + * Return: <0, 0, or >0 + * Programmer: Bill Wendling, 09. September 2002 + * Modifications: + */ +static int H5FP_object_lock_cmp(struct sap_obj_lock *o1, + struct sap_obj_lock *o2, + int cmparg) +{ + FUNC_ENTER_NOINIT(H5FP_object_lock_cmp); + assert(o1); + assert(o2); + cmparg = cmparg; + FUNC_LEAVE(HDmemcmp(o1->oid, o2->oid, sizeof(o1->oid))); +} + +/* + * Function: H5FP_new_object_lock + * Purpose: Create a new object lock. The locks are keyed off of the + * OID when they're inserted into the TBBT. There's a + * reference count so the same process can request the lock + * multiple times, if need be. The rank of the requesting + * process is kept around so that we can determine who + * wanted it in the first place. RW_LOCK tells us what kind + * of lock it is -- READ or WRITE. + * Return: Success: Pointer to SAP_OBJ_LOCK structure. + * Failure: NULL + * Programmer: Bill Wendling, 09. September 2002 + * Modifications: + */ +static struct sap_obj_lock * +H5FP_new_object_lock(const unsigned char *oid, unsigned int rank, + enum sap_obj_type obj_type, enum sap_lock_type rw_lock) +{ + struct sap_obj_lock *ret_value = NULL; + + FUNC_ENTER_NOINIT(H5FP_new_object_lock); + assert(oid); + + if ((ret_value = (struct sap_obj_lock *)HDmalloc(sizeof(struct sap_obj_lock))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "out of memory"); + + H5FP_COPY_OID(ret_value->oid, oid); + ret_value->owned_rank = rank; + ret_value->obj_type = obj_type; + ret_value->ref_count = 1; + ret_value->rw_lock = rw_lock; + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_free_object_lock + * Purpose: Free up the space allocated for the object lock. + * Return: SUCCEED (never fails) + * Programmer: Bill Wendling, 09. September 2002 + * Modifications: + */ +static herr_t +H5FP_free_object_lock(struct sap_obj_lock *ol) +{ + FUNC_ENTER_NOINIT(H5FP_free_object_lock); + HDfree(ol); + FUNC_LEAVE(SUCCEED); +} + +/* + * Function: H5FP_find_object_lock + * Purpose: Find the object lock for the given OID if there is one. + * Return: Pointer to the object or NULL. + * Programmer: Bill Wendling, 09. September 2002 + * Modifications: + */ +static struct sap_obj_lock * +H5FP_find_object_lock(struct sap_file_struct *fs, unsigned char *oid) +{ + struct sap_obj_lock *ret_value = NULL; + + FUNC_ENTER_NOINIT(H5FP_find_object_lock); + + assert(fs); + assert(oid); + + if (fs->locks && fs->locks->root) { + H5TB_NODE *node; + struct sap_obj_lock ol; + + H5FP_COPY_OID(ol.oid, oid); + + if ((node = H5TB_dfind(fs->locks, (void *)&ol, NULL)) == NULL) + HGOTO_ERROR(H5E_FPHDF5, H5E_NOTFOUND, NULL, "lock not found"); + + ret_value = (struct sap_obj_lock *)node->data; + } + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_remove_object_lock_from_list + * Purpose: Remove the object lock from the file structure's lock + * list. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 09. September 2002 + * Modifications: + */ +static herr_t +H5FP_remove_object_lock_from_list(struct sap_file_struct *fs, + struct sap_obj_lock *ol) +{ + H5TB_NODE *node; + herr_t ret_value = FAIL; + + FUNC_ENTER_NOINIT(H5FP_remove_object_lock_from_list); + + if ((node = H5TB_dfind(fs->locks, (void *)ol, NULL)) != NULL) { + H5FP_free_object_lock(H5TB_rem(&fs->locks->root, node, NULL)); + ret_value = SUCCEED; + } + + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_file_mod_cmp + * Purpose: Comparison function for the TBBT. + * Return: <0, 0, or >0 + * Programmer: Bill Wendling, 27. August, 2002 + * Modifications: + */ +static int +H5FP_file_mod_cmp(struct sap_file_mod *k1, struct sap_file_mod *k2, int cmparg) +{ + FUNC_ENTER_NOINIT(H5FP_file_mod_cmp); + assert(k1); + assert(k2); + cmparg = cmparg; /* shut compiler up */ + FUNC_LEAVE(k1->key - k2->key); +} + +/* + * Function: H5FP_new_file_mod_key + * Purpose: Generate a new key for the sap_file_mode structure. + * Return: Success: New key value. + * Failure: Doesn't. + * Programmer: Bill Wendling, 27. August, 2002 + * Modifications: + */ +static unsigned long +H5FP_new_file_mod_key(void) +{ + static unsigned long key = 0; + + FUNC_ENTER_NOINIT(H5FP_new_file_mod_key); + FUNC_LEAVE(key++); +} + +/* + * Function: H5FP_free_mod_node + * Purpose: Helper function to free up an SAP_FILE_MOD node and all + * of the malloced space it has. + * Return: Success: SUCCEED + * Failure: Doesn't fail + * Programmer: Bill Wendling, 31. July, 2002 + * Modifications: + */ +static herr_t +H5FP_free_mod_node(struct sap_file_mod *fs) +{ + FUNC_ENTER_NOINIT(H5FP_free_mod_node); + + if (fs) { + HDfree(fs->procs_notified); + HDfree(fs->metadata); + HDfree(fs); + } + + FUNC_LEAVE(SUCCEED); +} + +/* + * Function: H5FP_new_file_mod_node + * Purpose: Create a new sap_file_mod node and initialize it. + * Return: Success: Pointer to new sap_file_mod structure. + * Failure: NULL + * Programmer: Bill Wendling, 02. August, 2002 + * Modifications: + */ +static struct sap_file_mod * +H5FP_new_file_mod_node(unsigned rank, enum sap_obj_type obj_type, + enum sap_action action, int md_len, char *metadata) +{ + struct sap_file_mod *ret_value = NULL; + + FUNC_ENTER_NOINIT(H5FP_new_file_mod_node); + + ret_value = (struct sap_file_mod *)HDmalloc(sizeof(struct sap_file_mod)); + + if (!ret_value) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "out of memory"); + + ret_value->procs_notified = (unsigned char *)HDcalloc((size_t)1 + + (H5FP_comm_size - 1) / H5FP_BYTE_BITS, 1); + + if (!ret_value->procs_notified) { + HDfree(ret_value); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "out of memory"); + } + + /* we'll just assume the SAP has been notified of this change :) */ + SET_PROC_NOTIFIED(ret_value, H5FP_sap_rank); + SET_PROC_NOTIFIED(ret_value, rank); + ret_value->obj_type = obj_type; + ret_value->action = action; + ret_value->md_len = md_len; + ret_value->metadata = metadata; + ret_value->key = H5FP_new_file_mod_key(); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_add_file_mod_to_list + * Purpose: Add a modification to a file ID. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 02. August, 2002 + * Modifications: + */ +static herr_t +H5FP_add_file_mod_to_list(struct sap_file_struct *fs, enum sap_obj_type obj_type, + enum sap_action action, unsigned rank, int md_len, + char *metadata) +{ + struct sap_file_mod *fm; + herr_t ret_value = FAIL; + + FUNC_ENTER_NOINIT(H5FP_add_file_mod_to_list); + + assert(fs); + + if ((fm = H5FP_new_file_mod_node(rank, obj_type, action, md_len, metadata)) != NULL) { + if (!H5TB_dins(fs->mod_tree, (void *)fm, NULL)) + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTINSERT, FAIL, "can't insert modification into tree"); + + ret_value = SUCCEED; + } + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_remove_mod_from_list + * Purpose: Remove a modification from the list of modifications on + * this file. + * + * NOTE: Don't call this function directly. This should only be + * called after all processes for a particular modification have + * been synced. + * + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 31. July, 2002 + * Modifications: + */ +static herr_t +H5FP_remove_mod_from_list(struct sap_file_struct *fs, struct sap_file_mod *mod) +{ + H5TB_NODE *node; + herr_t ret_value = FAIL; + + FUNC_ENTER_NOINIT(H5FP_remove_mod_from_list); + + if ((node = H5TB_dfind(fs->mod_tree, (void *)mod, NULL)) != NULL) { + H5FP_free_mod_node(H5TB_rem(&fs->mod_tree->root, node, NULL)); + ret_value = SUCCEED; + } + + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_free_file_struct_node + * Purpose: Helper function to free up an SAP_FILE_STRUCT node and all + * of the malloced space it has. + * + * Note: It is an error to call this function before all + * modifications have been synced with all processes in the + * H5FP_SAP_COMM. + * Return: SUCCEED (never fails) + * Programmer: Bill Wendling, 31. July, 2002 + * Modifications: + */ +static herr_t +H5FP_free_file_struct_node(struct sap_file_struct *fs) +{ + FUNC_ENTER_NOINIT(H5FP_free_file_struct_node); + + if (fs) { + H5TB_dfree(fs->mod_tree, (void (*)(void*))H5FP_free_mod_node, NULL); + H5TB_dfree(fs->locks, (void (*)(void*))H5FP_free_object_lock, NULL); + HDfree(fs->filename); + HDfree(fs); + } + + FUNC_LEAVE(SUCCEED); +} + +/* + * Function: H5FP_file_struct_cmp + * Purpose: Compare two sap_file_struct structs for the TBBT. + * Return: <0, 0, >0 + * Programmer: Bill Wendling, 27. August, 2002 + * Modifications: + */ +static int +H5FP_file_struct_cmp(struct sap_file_struct *k1, struct sap_file_struct *k2, int cmparg) +{ + FUNC_ENTER_NOINIT(H5FP_file_struct_cmp); + assert(k1); + assert(k2); + cmparg = cmparg; /* shut compiler up */ + FUNC_LEAVE(k1->sap_file_id - k2->sap_file_id); +} + +/* + * Function: H5FP_new_file_struct_node + * Purpose: Create and initialize an sap_file_struct node. + * Return: Success: Pointer to new node + * Failure: NULL + * Programmer: Bill Wendling, 02. August, 2002 + * Modifications: + */ +static struct sap_file_struct * +H5FP_new_file_struct_node(unsigned int sap_file_id, char *filename) +{ + struct sap_file_struct *ret_value; + + FUNC_ENTER_NOINIT(H5FP_new_file_struct_node); + + if ((ret_value = (struct sap_file_struct *)HDmalloc(sizeof(struct sap_file_struct))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "out of memory"); + + ret_value->sap_file_id = sap_file_id; + ret_value->filename = filename; + ret_value->closing = 0; + ret_value->mod_tree = NULL; + ret_value->locks = NULL; + + if ((ret_value->mod_tree = H5TB_dmake((H5TB_cmp_t)H5FP_file_mod_cmp, + sizeof(struct sap_file_mod), FALSE)) == NULL) { + H5FP_free_file_struct_node(ret_value); + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTMAKETREE, NULL, "cannot make TBBT tree"); + } + + if ((ret_value->locks = H5TB_dmake((H5TB_cmp_t)H5FP_object_lock_cmp, + sizeof(struct sap_obj_lock), FALSE)) == NULL) { + H5FP_free_file_struct_node(ret_value); + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTMAKETREE, NULL, "cannot make TBBT tree"); + } + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_find_file_struct + * Purpose: Find the file structure for the requested sap_file_id. + * Return: Success: Pointer to the file structure + * Failure: NULL + * Programmer: Bill Wendling, 31. July, 2002 + * Modifications: + */ +static struct sap_file_struct * +H5FP_find_file_struct(unsigned int sap_file_id) +{ + H5TB_NODE *node = NULL; + struct sap_file_struct *ret_value = NULL; + + FUNC_ENTER_NOINIT(H5FP_find_file_struct); + + if (fs_tree && fs_tree->root) { + struct sap_file_struct s; + + s.sap_file_id = sap_file_id; + + if ((node = H5TB_dfind(fs_tree, (void *)&s, NULL)) != NULL) + ret_value = (struct sap_file_struct *)node->data; + } + + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_add_new_file_struct_to_list + * Purpose: Add an SAP_FILE_ID to the list of file IDS. + * Return: SUCCEED if the node was added + * FAIL otherwise + * Programmer: Bill Wendling, 02. August, 2002 + * Modifications: + */ +static herr_t +H5FP_add_new_file_struct_to_list(unsigned int sap_file_id, char *filename) +{ + struct sap_file_struct *fs; + herr_t ret_value = FAIL; + + FUNC_ENTER_NOINIT(H5FP_add_new_file_struct_to_list); + + if ((fs = H5FP_new_file_struct_node(sap_file_id, filename)) != NULL) { + if (!H5TB_dins(fs_tree, (void *)fs, NULL)) + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTINSERT, FAIL, "can't insert file structure into tree"); + + ret_value = SUCCEED; + } + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_remove_file_id_from_list + * Purpose: Remove an SAP_FILE_ID from the list of file IDS. + * + * NOTE: This should only be called after all modifications to + * the file descriptor have been synced to all processes and the + * file has been closed by all processes. + * + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 31. July, 2002 + * Modifications: + */ +static herr_t +H5FP_remove_file_id_from_list(unsigned int sap_file_id) +{ + struct sap_file_struct s; + H5TB_NODE *node; + herr_t ret_value = FAIL; + + FUNC_ENTER_NOINIT(H5FP_remove_file_id_from_list); + + s.sap_file_id = sap_file_id; + + if ((node = H5TB_dfind(fs_tree, (void *)&s, NULL)) != NULL) { + H5FP_free_file_struct_node(H5TB_rem(&fs_tree->root, node, NULL)); + ret_value = SUCCEED; + } + + FUNC_LEAVE(ret_value); +} + +/** Functions to reply to requests **/ + +static herr_t +H5FP_send_reply(unsigned int to, unsigned int req_id, unsigned int file_id, + enum sap_status status) +{ + struct SAP_reply reply; + herr_t ret_value = SUCCEED; + int mrc; + + FUNC_ENTER_NOINIT(H5FP_send_reply); + + reply.req_id = req_id; + reply.sap_file_id = file_id; + reply.status = status; + + if ((mrc = MPI_Send(&reply, 1, SAP_reply_t, (int)to, H5FP_TAG_REPLY, + H5FP_SAP_COMM)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + +done: + FUNC_LEAVE(ret_value); +} + +/** Functions to handle SAP requests **/ + +/* + * Function: H5FP_gen_request_id + * Purpose: Generate a unique request ID to send along with a + * message. + * Return: Integer >= 0 - Doesn't fail. + * Programmer: Bill Wendling, 30. July, 2002 + * Modifications: + */ +static unsigned int +H5FP_gen_sap_file_id() +{ + static unsigned int i = 0; + FUNC_ENTER_NOINIT(H5FP_gen_sap_file_id); + FUNC_LEAVE(i++); +} + +/* + * Function: H5FP_sap_handle_open_request + * Purpose: Handle a request to open a file. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 06. August, 2002 + * Modifications: + */ +static herr_t +H5FP_sap_handle_open_request(struct SAP_request req, char *mdata, int md_len) +{ + herr_t ret_value = SUCCEED; + int mrc; + + FUNC_ENTER_NOINIT(H5FP_sap_handle_open_request); + + if (req.obj_type == H5FP_OBJ_FILE) { + unsigned new_file_id = H5FP_gen_sap_file_id(); + int i; + + if (H5FP_add_new_file_struct_to_list(new_file_id, mdata) != SUCCEED) + /* FIXME: This should be a different error message */ + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTINSERT, FAIL, "can't insert file structure into tree"); + + /* broadcast the file id to all processes */ + for (i = 0; i < H5FP_comm_size; ++i) + if ((unsigned)i != H5FP_sap_rank) + if ((mrc = MPI_Send(&new_file_id, 1, MPI_UNSIGNED, i, + H5FP_TAG_FILE_ID, H5FP_SAP_COMM)) != MPI_SUCCESS) + /* + * FIXME: This is terrible...if we can't send to all + * processes, we should clean the file structure from + * the list and tell all of the other processes that + * we couldn't continue...but how to do that?!? + */ + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + printf("broadcast %d from %d\n", new_file_id, H5FP_sap_rank); + HDfflush(stdout); + } + + md_len = md_len; + printf("request_type == H5FP_REQ_OPEN, request_id == %d, proc_rank == %d,\n" + "sap_file_id == %d, obj_type == %d, action == %d\n", + req.req_id, req.proc_rank, req.sap_file_id, req.obj_type, + req.action); + HDfflush(stdout); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_sap_handle_lock_request + * Purpose: Handle a request to lock an object. There are two + * different kinds of locks. There are READ and WRITE locks. + * The READ locks are sharable, that is if all processes want + * to READ the object, they can. They just tell the SAP that + * they're doing so and the SAP gives them a "token" to do + * that. WRITE locks, on the other hand, are exclusive. You + * can't have any outstanding READ or WRITE locks on an + * object before you get a WRITE lock on it. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 06. August, 2002 + * Modifications: + */ +static herr_t +H5FP_sap_handle_lock_request(struct SAP_request req) +{ + struct lock_group { + unsigned char oid[sizeof(req.oid)]; + unsigned int file_id; + unsigned int locked; + enum sap_lock_type rw_lock; + struct sap_file_struct *fs; + struct sap_obj_lock *lock; + } *oids; + int list_size = 2; /* the size of the "oids" list */ + enum sap_status exit_state = H5FP_STATUS_LOCK_ACQUIRED; + herr_t ret_value = SUCCEED; + int i, j; + + FUNC_ENTER_NOINIT(H5FP_sap_handle_lock_request); + + if ((oids = (struct lock_group *)HDmalloc(list_size * sizeof(struct lock_group))) == NULL) { + exit_state = H5FP_STATUS_OOM; + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "out of memory"); + } + + /* + * Gather together all of the OIDs the process is requesting to lock + * at one time. + */ + for (i = 0;; ++i) { + if (req.oid[0]) { + if (i == list_size) { + list_size *= 2; + oids = HDrealloc(oids, list_size * sizeof(struct lock_group)); + + if (!oids) { + exit_state = H5FP_STATUS_OOM; + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "out of memory"); + } + } + + H5FP_COPY_OID(oids[i].oid, req.oid); + oids[i].file_id = req.sap_file_id; + oids[i].rw_lock = req.rw_lock; + oids[i].locked = FALSE; + } + + if (req.req_type == H5FP_REQ_LOCK_END) + /* this was the last lock request */ + break; + + if (H5FP_sap_receive(&req, (int)req.proc_rank, + H5FP_TAG_REQUEST, NULL) != SUCCEED) { + exit_state = H5FP_STATUS_LOCK_FAILED; + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTRECV, FAIL, "cannot receive messages"); + } + } + + /* + * Check to see if we can acquire all of the locks requested. If + * not, the it's an error and we need to return. + */ + for (j = 0; j <= i; ++j) { + if ((oids[j].fs = H5FP_find_file_struct(oids[j].file_id)) == NULL) { + /* FIXME: the file ID is invalid */ + exit_state = H5FP_STATUS_BAD_FILE_ID; + HGOTO_DONE(FAIL); + } + + if (oids[j].fs->closing) { + /* we're closing the file - don't accept anymore locks */ + exit_state = H5FP_STATUS_FILE_CLOSING; + HGOTO_DONE(FAIL); + } + + oids[j].lock = H5FP_find_object_lock(oids[j].fs, oids[j].oid); + + /* + * Don't panic! + * + * This horrid little if-then statement is just the logical + * inverse of the if-then statement in the next for-loop. + */ + if (oids[j].lock && + !((oids[j].rw_lock == H5FP_LOCK_READ && + oids[j].lock->rw_lock == H5FP_LOCK_READ) || + (oids[j].rw_lock == H5FP_LOCK_WRITE && + oids[j].lock->rw_lock == H5FP_LOCK_WRITE && + oids[j].lock->owned_rank == req.proc_rank))) { + /* FAILURE */ + exit_state = H5FP_STATUS_LOCK_FAILED; + HGOTO_DONE(FAIL); + } + } + + /* + * Actually acquire the locks. This shouldn't fail because of the + * previous check. The only thing which can likely occur is an + * out-of-memory error. + */ + for (j = 0; j <= i; ++j) { + if (oids[j].lock) { + /* + * Don't panic! + * + * This horrid little if-then statement is just checking so + * that if you want a READ lock and the current lock is a + * READ lock, then we bump up the reference count on it. If + * you want a WRITE lock and the current lock is a WRITE lock + * and furthermore the current process has that lock, we will + * also bump up the reference count. + * + * Otherwise, it's a failure. + */ + if ((oids[j].rw_lock == H5FP_LOCK_READ && + oids[j].lock->rw_lock == H5FP_LOCK_READ) || + (oids[j].rw_lock == H5FP_LOCK_WRITE && + oids[j].lock->rw_lock == H5FP_LOCK_WRITE && + oids[j].lock->owned_rank == req.proc_rank)) { + /* + * The requesting process may already have this lock. Might + * be a request from some call-back function of some sort. + * Increase the reference count (which is decreased when + * released) to help to prevent deadlocks. + */ + ++oids[j].lock->ref_count; + oids[j].locked = TRUE; + } else { + /* FIXME: reply saying object locked? */ + exit_state = H5FP_STATUS_LOCK_FAILED; + ret_value = FAIL; + goto rollback; + } + } else { + struct sap_obj_lock *lock = H5FP_new_object_lock(oids[j].oid, req.proc_rank, + req.obj_type, req.rw_lock); + + if (lock) { + if (!H5TB_dins(oids[j].fs->locks, (void *)lock, NULL)) { + H5FP_free_object_lock(lock); + exit_state = H5FP_STATUS_LOCK_FAILED; + ret_value = FAIL; + HCOMMON_ERROR(H5E_FPHDF5, H5E_CANTINSERT, "can't insert lock into tree"); + goto rollback; + } + + oids[j].locked = TRUE; + } else { + /* out of memory...ulp! */ + exit_state = H5FP_STATUS_OOM; + ret_value = FAIL; + HCOMMON_ERROR(H5E_RESOURCE, H5E_NOSPACE, "out of memory"); + goto rollback; + } + } + } + + printf("request_type == H5FP_REQ_LOCK, request_id == %d, proc_rank == %d,\n" + "sap_file_id == %d, obj_type == %d, action == %d\n", + req.req_id, req.proc_rank, req.sap_file_id, req.obj_type, + req.action); + HDfflush(stdout); + + goto done; + + /* Error handling code */ +rollback: + /* + * More than likely, out of memory during the actual locking phase. + * Try to release any locks which may have been obtained. If it's not + * possible to release those locks, we're in big trouble. The file is + * now in an inconsistent state, as far as the SAP is concerned. The + * only options left to the program are either to abort or completely + * close the file and reopen. + */ + for (j = 0; j <= i; ++j) { + if (oids[j].locked) { + if (oids[j].lock) { + if (oids[j].lock->owned_rank == req.proc_rank) { + if (--oids[j].lock->ref_count == 0) { + H5FP_remove_object_lock_from_list(oids[j].fs, oids[j].lock); + } + } else { + /* CATASTROPHIC FAILURE!!! */ + /* LOCK WAS NOT CLEARED */ + exit_state = H5FP_STATUS_CATASTROPHIC; + } + } else { + /* CATASTROPHIC FAILURE!!! */ + /* LOCK WAS NOT CLEARED */ + exit_state = H5FP_STATUS_CATASTROPHIC; + } + } + } + +done: + if (ret_value != SUCCEED) { + /* Can't lock the whole group at one time for some reason */ + printf("locking failure!!\n"); + HDfflush(stdout); + } + + HDfree(oids); + H5FP_send_reply(req.proc_rank, req.req_id, req.sap_file_id, exit_state); + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_sap_handle_release_lock_request + * Purpose: Handle a request to release the lock on an object. + * Return: Nothing + * Programmer: Bill Wendling, 06. August, 2002 + * Modifications: + */ +static herr_t +H5FP_sap_handle_release_lock_request(struct SAP_request req) +{ + struct release_group { + unsigned char oid[sizeof(req.oid)]; + unsigned int file_id; + struct sap_file_struct *fs; + struct sap_obj_lock *lock; + } *oids; + int list_size = 2; /* the size of the "oids" list */ + enum sap_status exit_state = H5FP_STATUS_LOCK_RELEASED; + herr_t ret_value; + int i, j; + + FUNC_ENTER_NOINIT(H5FP_sap_handle_release_lock_request); + + if ((oids = (struct release_group *)HDmalloc(list_size * + sizeof(struct release_group))) == NULL) { + exit_state = H5FP_STATUS_OOM; + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "out of memory"); + } + + /* + * Gather together all of the OIDs the process is requesting to + * release locks at one time. + */ + for (i = 0;; ++i) { + if (req.oid[0]) { + if (i == list_size) { + list_size *= 2; + oids = HDrealloc(oids, list_size * sizeof(struct release_group)); + + if (!oids) { + exit_state = H5FP_STATUS_OOM; + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "out of memory"); + } + } + + H5FP_COPY_OID(oids[i].oid, req.oid); + oids[i].file_id = req.sap_file_id; + } + + if (req.req_type == H5FP_REQ_RELEASE_END) + /* this was the last lock request */ + break; + + if (H5FP_sap_receive(&req, (int)req.proc_rank, H5FP_TAG_REQUEST, NULL) != SUCCEED) { + exit_state = H5FP_STATUS_LOCK_RELEASE_FAILED; + HGOTO_DONE(FAIL); + } + } + + /* + * Check here to see if the locks exist and we have the locks. This + * will help keep us from being in a catastrophic state. + */ + for (j = 0; j <= i; ++j) { + if ((oids[j].fs = H5FP_find_file_struct(oids[j].file_id)) == NULL) { + /* FIXME: the file ID is invalid */ + exit_state = H5FP_STATUS_BAD_FILE_ID; + HGOTO_DONE(FAIL); + } + + oids[j].lock = H5FP_find_object_lock(oids[j].fs, oids[j].oid); + + if (!oids[j].lock || oids[j].lock->owned_rank != req.proc_rank) { + exit_state = H5FP_STATUS_BAD_LOCK; + HGOTO_DONE(FAIL); + } + } + + /* + * Release a lock. There may be multiple locks to release if they + * were locked in a group, so loop finding all of the locks and + * release them. + */ + for (j = 0; j <= i; ++j) { + if (oids[j].lock) { + if (oids[j].lock->owned_rank == req.proc_rank) { + if (--oids[j].lock->ref_count == 0) + H5FP_remove_object_lock_from_list(oids[j].fs, oids[j].lock); + } else { + /* AAAIIIIEEE!!! */ + exit_state = H5FP_STATUS_CATASTROPHIC; + HGOTO_DONE(FAIL); + } + } else { + /* AAAIIIIEEE!!! */ + exit_state = H5FP_STATUS_CATASTROPHIC; + HGOTO_DONE(FAIL); + } + } + + printf("request_type == H5FP_REQ_RELEASE, request_id == %d, proc_rank == %d,\n" + "sap_file_id == %d, obj_type == %d, action == %d\n", + req.req_id, req.proc_rank, req.sap_file_id, req.obj_type, + req.action); + + HDfflush(stdout); + +done: + HDfree(oids); + H5FP_send_reply(req.proc_rank, req.req_id, req.sap_file_id, exit_state); + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_sap_handle_change_request + * Purpose: Handle a request to change the structure of an object. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 06. August, 2002 + * Modifications: + */ +static herr_t +H5FP_sap_handle_change_request(struct SAP_request req, char *mdata, int md_len) +{ + struct sap_file_struct *fs; + enum sap_status exit_state = H5FP_STATUS_OK; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOINIT(H5FP_sap_handle_change_request); + + if ((fs = H5FP_find_file_struct(req.sap_file_id)) != NULL) { + if (fs->closing) { + /* we're closing the file - don't accept anymore changes */ + exit_state = H5FP_STATUS_FILE_CLOSING; + ret_value = FAIL; + } else { + /* handle the change request */ + struct sap_obj_lock *lock = H5FP_find_object_lock(fs, req.oid); + + if (!lock || lock->owned_rank != req.proc_rank + || lock->rw_lock != H5FP_LOCK_WRITE) { + /* + * There isn't a write lock or we don't own the write + * lock on this OID + */ + exit_state = H5FP_STATUS_NO_LOCK; + ret_value = FAIL; + } else if (H5FP_add_file_mod_to_list(fs, req.obj_type, req.action, + req.proc_rank, md_len, mdata) != SUCCEED) { + exit_state = H5FP_STATUS_OOM; + ret_value = FAIL; + } + } + } else { + /* error: there isn't a file opened to change */ + exit_state = H5FP_STATUS_BAD_FILE_ID; + ret_value = FAIL; + } + + printf("request_type == H5FP_REQ_CHANGE, request_id == %d, proc_rank == %d,\n" + "sap_file_id == %d, obj_type == %d, action == %d\n", + req.req_id, req.proc_rank, req.sap_file_id, req.obj_type, + req.action); + printf("metadata received == %s, len == %d\n", mdata, md_len); + + H5FP_send_reply(req.proc_rank, req.req_id, req.sap_file_id, exit_state); + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_sap_handle_sync_request + * Purpose: Handle a request to sync changes to a file with the requesting + * process. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 06. August, 2002 + * Modifications: + */ +static herr_t +H5FP_sap_handle_sync_request(struct SAP_request req) +{ + struct sap_file_struct *fs; + struct SAP_sync s; + herr_t ret_value = SUCCEED; + int mrc, sync_id = 0; + + FUNC_ENTER_NOINIT(H5FP_sap_handle_sync_request); + + s.req_id = req.req_id; + s.sap_file_id = req.sap_file_id; + s.last_msg = FALSE; + s.md_len = 0; + s.obj_type = 0; + s.action = 0; + s.status = H5FP_STATUS_OK; + + if ((fs = H5FP_find_file_struct(req.sap_file_id)) != NULL) { + if (fs->mod_tree->root) { + H5TB_NODE *mod_node = H5TB_first(fs->mod_tree->root); + + while (mod_node) { + struct sap_file_mod *mod = (struct sap_file_mod *)mod_node->data; + + if (mod && !IS_PROC_NOTIFIED(mod, req.proc_rank)) { + s.sync_id = sync_id++; + s.md_len = mod->md_len; + s.obj_type = mod->obj_type; + s.action = mod->action; + + if ((mrc = MPI_Send(&s, 1, SAP_sync_t, (int)req.proc_rank, + H5FP_TAG_SYNC, H5FP_SAP_COMM)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + + if (H5FP_send_metadata(mod->metadata, mod->md_len, (int)req.proc_rank) + != SUCCEED) + HGOTO_ERROR(H5E_FPHDF5, H5E_CANTSENDMDATA, FAIL, + "can't send metadata to client"); + + SET_PROC_NOTIFIED(mod, req.proc_rank); + } + + /* + * check to see if this modification has been sent to all + * clients + */ + if (mod->num_notified == (unsigned)H5FP_comm_size) + if (H5FP_remove_mod_from_list(fs, mod) == FAIL) + HGOTO_ERROR(H5E_FPHDF5, H5E_NOTFOUND, FAIL, "cannot remove modification"); + + mod_node = H5TB_next(mod_node); + } + } + } else { + s.status = H5FP_STATUS_BAD_FILE_ID; + } + + s.sync_id = sync_id; + s.last_msg = TRUE; + + if ((mrc = MPI_Send(&s, 1, SAP_sync_t, (int)req.proc_rank, + H5FP_TAG_SYNC, H5FP_SAP_COMM)) != MPI_SUCCESS) + HMPI_GOTO_ERROR(FAIL, "MPI_Send failed", mrc); + + printf("request_type == H5FP_REQ_SYNC, request_id == %d, proc_rank == %d,\n" + "sap_file_id == %d, obj_type == %d, action == %d\n", + req.req_id, req.proc_rank, req.sap_file_id, req.obj_type, + req.action); + HDfflush(stdout); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5FP_sap_handle_close_request + * Purpose: Handle a request to close a file. + * Return: Success: SUCCEED + * Failure: FAIL + * Programmer: Bill Wendling, 06. August, 2002 + * Modifications: + */ +static herr_t +H5FP_sap_handle_close_request(struct SAP_request req) +{ + struct sap_file_struct *fs; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOINIT(H5FP_sap_handle_close_request); + + if ((fs = H5FP_find_file_struct(req.sap_file_id)) != NULL) { + /* do a sync with the closing process */ + if (H5FP_sap_handle_sync_request(req) != SUCCEED) + HGOTO_ERROR(H5E_FPHDF5, H5E_NOTFOUND, FAIL, "couldn't sync with process"); + + if (++fs->closing == H5FP_comm_size - 1) + /* all processes have closed the file - remove it from list */ + if (H5FP_remove_file_id_from_list(req.sap_file_id) != SUCCEED) + HGOTO_ERROR(H5E_FPHDF5, H5E_NOTFOUND, FAIL, "cannot remove file ID from list"); + } + + printf("request_type == H5FP_REQ_CLOSE, request_id == %d, proc_rank == %d,\n" + "sap_file_id == %d, obj_type == %d, action == %d\n", + req.req_id, req.proc_rank, req.sap_file_id, req.obj_type, + req.action); + +done: + FUNC_LEAVE(ret_value); +} + +#endif /* H5_HAVE_FPHDF5 */ diff --git a/src/H5Ofphdf5.c b/src/H5Ofphdf5.c new file mode 100644 index 0000000..a93611b --- /dev/null +++ b/src/H5Ofphdf5.c @@ -0,0 +1,519 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* $Id$ */ + +#define H5P_PACKAGE /* prevent warning from including H5Ppkg.h */ +#define H5S_PACKAGE /* prevent warning from including H5Spkg.h */ + +#include "H5private.h" /* Generic functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free lists */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Oprivate.h" /* Object headers */ +#include "H5Rprivate.h" +#include "H5Ppkg.h" +#include "H5Spkg.h" + +#if defined (WIN32) && !defined (__MWERKS__) +#include +#include +#endif + +#ifdef H5_HAVE_FPHDF5 + +#define PABLO_MASK H5O_fphdf5_mask + +/* local prototypes */ +static void *H5O_fphdf5_decode(H5F_t *f, const uint8_t *p, H5O_shared_t *sh); +static herr_t H5O_fphdf5_encode(H5F_t *f, uint8_t *p, const void *_mesg); +static size_t H5O_fphdf5_size(H5F_t *f, const void *_mesg); +static herr_t H5O_fphdf5_reset(void *_mesg); +static herr_t H5O_fphdf5_free(void *_mesg); +static herr_t H5O_fphdf5_debug(H5F_t *f, const void *_mesg, + FILE *stream, int indent, int fwidth); + +/* This message derives from H5O */ +const H5O_class_t H5O_FPHDF5[1] = {{ + H5O_FPHDF5_ID, /* message id number */ + "fphdf5", /* message name for debugging */ + sizeof(H5O_fphdf5_t), /* native message size */ + H5O_fphdf5_decode, /* decode message */ + H5O_fphdf5_encode, /* encode message */ + NULL, /* copy the native value */ + H5O_fphdf5_size, /* size of symbol table entry */ + H5O_fphdf5_reset, /* default reset method */ + H5O_fphdf5_free, /* free method */ + NULL, /* get share method */ + NULL, /* set share method */ + H5O_fphdf5_debug, /* debug the message */ +}}; + +#define H5O_FPHDF5_VERSION 1 + +/* Is the interface initialized? */ +static int interface_initialize_g = 0; + +#define INTERFACE_INIT NULL + +/* Define the free list for H5O_fphdf5_t's */ +H5FL_DEFINE_STATIC(H5O_fphdf5_t); + +/* Declare external the free list for hsize_t arrays */ +H5FL_ARR_EXTERN(hsize_t); + +/* + * Function: H5O_fphdf5_decode + * Purpose: Decode a metadata message from the SAP and return a pointer to + * a memory struct with the decoded information. + * + * This function decodes the "raw" form of a metadata message + * sent from the SAP into a struct in memory native format. The + * struct is allocated within this function using malloc() and is + * returned to the caller. + * + * H5F_t *f IN: pointer to the HDF5 file struct + * uint8 *p OUT: the raw information buffer + * H5O_shared_t *sh IN: not used; must be NULL + * + * Return: Success: Pointer to the new message in native order + * Failure: NULL + * Programmer: Bill Wendling, 20. August 2002 + * Modifications: + */ +static void * +H5O_fphdf5_decode(H5F_t *f, const uint8_t *p, H5O_shared_t UNUSED *sh) +{ + H5O_fphdf5_t *fmeta = NULL; /* New FPHDF5 metadata structure */ + void *ret_value; + unsigned int i; + + FUNC_ENTER_NOAPI(H5O_fphdf5_decode, NULL); + + /* check args */ + assert(f); + assert(p); + assert(!sh); + + /* decode */ + fmeta = H5FL_ALLOC(H5O_fphdf5_t, 1); + + /* decode the OID first */ + for (i = 0; i < sizeof(fmeta->oid); ++i) + fmeta->oid[i] = p[i]; + + /* jump past the OID part */ + p += sizeof(fmeta->oid); + + /* decode the dataspace dimensions next */ + fmeta->sdim = H5O_SDSPACE[0].decode(f, p, NULL); + + if (!fmeta->sdim) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* jump past the dataspace dimensions part */ + p += H5O_SDSPACE[0].raw_size(f, fmeta->sdim); + + /* decode the datatype next */ + fmeta->dtype = H5O_DTYPE[0].decode(f, p, NULL); + + if (!fmeta->dtype) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* jump past the datatype part */ + p += H5O_DTYPE[0].raw_size(f, fmeta->dtype); + + /* decode the modification time next */ + fmeta->mtime = H5O_DTYPE[0].decode(f, p, NULL); + + if (!fmeta->dtype) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* jump past the modification time part */ + p += H5O_MTIME[0].raw_size(f, fmeta->mtime); + + /* decode the group the modification took place in */ + fmeta->group = H5O_NAME[0].decode(f, p, NULL); + + if (!fmeta->group) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* jump past the group name part */ + p += H5O_NAME[0].raw_size(f, fmeta->group); + + /* decode the dataset the modification took place in */ + fmeta->dset = H5O_NAME[0].decode(f, p, NULL); + + if (!fmeta->dset) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* jump past the dataset name part */ + p += H5O_NAME[0].raw_size(f, fmeta->dset); + + /* decode the property list last */ + fmeta->plist = H5O_PLIST[0].decode(f, p, NULL); + + if (!fmeta->plist) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* Set return value */ + ret_value = (void *)fmeta; /*success*/ + +done: + if (!ret_value && fmeta) { + /* free up fmeta */ + if (H5O_SDSPACE[0].free) + H5O_SDSPACE[0].free(fmeta->sdim); + + if (H5O_DTYPE[0].free) + H5O_DTYPE[0].free(fmeta->dtype); + + if (H5O_MTIME[0].free) + H5O_MTIME[0].free(fmeta->mtime); + + if (H5O_PLIST[0].free) + H5O_PLIST[0].free(fmeta->plist); + + H5FL_FREE(H5O_fphdf5_t, fmeta); + } + + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_fphdf5_encode + * Purpose: Encode a metadata message for the SAP and return a pointer to + * a memory struct with the encoded information. + * + * This function encodes the "raw" form of a metadata message + * sent from the SAP into a struct in memory native format. + * + * H5F_t *f IN: pointer to the HDF5 file struct + * uint8 *p OUT: the raw information buffer + * const void *mesg IN: pointer to the metadata to encode + * + * Return: Success: Non-negative + * Failure: Negative + * Programmer: Bill Wendling, 21. August 2002 + * Modifications: + */ +static herr_t +H5O_fphdf5_encode(H5F_t *f, uint8_t *p, const void *mesg) +{ + const H5O_fphdf5_t *fmeta = (const H5O_fphdf5_t *)mesg; + herr_t ret_value = SUCCEED; + unsigned int i; + + FUNC_ENTER_NOAPI(H5O_fphdf5_encode, FAIL); + + /* check args */ + assert(f); + assert(p); + assert(fmeta); + + /* encode the OID first */ + for (i = 0; i < sizeof(fmeta->oid); ++i) + p[i] = fmeta->oid[i]; + + /* jump past the OID part */ + p += sizeof(fmeta->oid); + + /* encode the dataspace dimensions next */ + ret_value = H5O_SDSPACE[0].encode(f, p, fmeta->sdim); + + if (ret_value < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + + /* jump past the dataspace dimensions part */ + p += H5O_SDSPACE[0].raw_size(f, fmeta->sdim); + + /* encode the datatype next */ + ret_value = H5O_DTYPE[0].encode(f, p, fmeta->dtype); + + if (ret_value < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + + /* jump past the datatype part */ + p += H5O_DTYPE[0].raw_size(f, fmeta->dtype); + + /* encode the modification time next */ + ret_value = H5O_DTYPE[0].encode(f, p, fmeta->mtime); + + if (ret_value < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + + /* jump past the modification time part */ + p += H5O_MTIME[0].raw_size(f, fmeta->mtime); + + /* encode the group name next */ + ret_value = H5O_NAME[0].encode(f, p, fmeta->group); + + if (ret_value < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + + /* jump past the group name part */ + p += H5O_NAME[0].raw_size(f, fmeta->group); + + /* encode the dataset name next */ + ret_value = H5O_NAME[0].encode(f, p, fmeta->dset); + + if (ret_value < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + + /* jump past the dataset name part */ + p += H5O_NAME[0].raw_size(f, fmeta->dset); + + /* decode the property list last */ + ret_value = H5O_PLIST[0].encode(f, p, fmeta->plist); + + if (ret_value < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_fphdf5_copy + * Purpose: Copies a metadata object from MESG to DEST allocating DEST if + * necessary. + * + * const void *mesg IN: pointer to the metadata to copy + * const void *dest OUT: pointer to the destination metadata struct + * + * Return: Success: Pointer to DEST + * Failure: NULL + * Programmer: Bill Wendling, 21. August 2002 + * Modifications: + */ +static void * +H5O_fphdf5_copy(const void *mesg, void *dest) +{ + const H5O_fphdf5_t *src = (const H5O_fphdf5_t *)mesg; + H5O_fphdf5_t *dst = (H5O_fphdf5_t *)dest; + void *ret_value; + unsigned int i; + + FUNC_ENTER_NOAPI(H5O_fphdf5_copy, NULL); + + /* check args */ + assert(src); + + if (!dst && NULL == (dst = H5FL_ALLOC(H5O_fphdf5_t, 0))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* copy the individual metadata*/ + for (i = 0; i < sizeof(src->oid); ++i) + dst->oid[i] = src->oid[i]; + + H5O_SDSPACE[0].copy(src->sdim, dst->sdim); + H5O_DTYPE[0].copy(src->dtype, dst->dtype); + H5O_MTIME[0].copy(src->mtime, dst->mtime); + H5O_NAME[0].copy(src->group, dst->group); + H5O_NAME[0].copy(src->dset, dst->dset); + + if (H5O_PLIST[0].copy) + H5O_PLIST[0].copy(src->plist, dst->plist); + + /* Set return value */ + ret_value = dst; + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_fphdf5_size + * Purpose: Return the raw message size in bytes. + * + * This function returns the size of hte raw simple + * dimensionality, datatype, and object path message on succes. + * (Not counting the message type or size fields, only the data + * portion of the message). It doesn't take into account + * alignment. + * + * H5F_t *f IN: pointer to the HDF5 file struct + * const void *mesg IN: pointer to the metadata structure + * + * Return: Success: Size of message + * Failure: 0 + * Programmer: Bill Wendling, 21. August 2002 + * Modifications: + */ +static size_t +H5O_fphdf5_size(H5F_t *f, const void *mesg) +{ + const H5O_fphdf5_t *fmeta = (const H5O_fphdf5_t *)mesg; + size_t ret_value; + + FUNC_ENTER_NOAPI(H5O_fphdf5_size, 0); + + /* add in the metadata sizes */ + ret_value = sizeof(fmeta->oid); + ret_value += H5O_SDSPACE[0].raw_size(f, fmeta->sdim); + ret_value += H5O_DTYPE[0].raw_size(f, fmeta->dtype); + ret_value += H5O_MTIME[0].raw_size(f, fmeta->mtime); + ret_value += H5O_NAME[0].raw_size(f, fmeta->group); + ret_value += H5O_NAME[0].raw_size(f, fmeta->dset); + ret_value += H5O_PLIST[0].raw_size(f, fmeta->plist); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_fphdf5_reset + * Purpose: Frees the inside of a metadata message and resets it to some + * initial value. + * + * const void *mesg IN: pointer to the metadata to reset + * + * Return: Success: Non-negative + * Failure: Negative + * Programmer: Bill Wendling, 21. August 2002 + * Modifications: + */ +static herr_t +H5O_fphdf5_reset(void *mesg) +{ + H5O_fphdf5_t *fmeta = (H5O_fphdf5_t *)mesg; + herr_t ret_value = SUCCEED; + unsigned int i; + + FUNC_ENTER_NOAPI(H5O_fphdf5_reset, FAIL); + + /* reset the metadata */ + for (i = 0; i < sizeof(fmeta->oid); ++i) + fmeta->oid[i] = '\0'; + + if (H5O_SDSPACE[0].reset) + ret_value = H5O_SDSPACE[0].reset(fmeta->sdim); + + if (H5O_DTYPE[0].reset) + ret_value = H5O_DTYPE[0].reset(fmeta->dtype); + + if (H5O_MTIME[0].reset) + ret_value = H5O_MTIME[0].reset(fmeta->mtime); + + if (H5O_NAME[0].reset) + ret_value = H5O_NAME[0].reset(fmeta->group); + + if (H5O_NAME[0].reset) + ret_value = H5O_NAME[0].reset(fmeta->dset); + + if (H5O_PLIST[0].reset) + ret_value = H5O_PLIST[0].reset(fmeta->plist); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_fphdf5_free + * Purpose: Free's the message + * + * const void *mesg IN: pointer to the metadata to free + * + * Return: Success: Non-negative + * Failure: Negative + * Programmer: Bill Wendling, 21. August 2002 + * Modifications: + */ +static herr_t +H5O_fphdf5_free(void *mesg) +{ + H5O_fphdf5_t *fmeta = (H5O_fphdf5_t *)mesg; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5O_fphdf5_free, FAIL); + assert(fmeta); + + /* reset the metadata */ + if (H5O_SDSPACE[0].free) + ret_value = H5O_SDSPACE[0].free(fmeta->sdim); + + if (H5O_DTYPE[0].free) + ret_value = H5O_DTYPE[0].free(fmeta->dtype); + + if (H5O_MTIME[0].free) + ret_value = H5O_MTIME[0].free(fmeta->mtime); + + if (H5O_NAME[0].free) + ret_value = H5O_NAME[0].free(fmeta->group); + + if (H5O_NAME[0].free) + ret_value = H5O_NAME[0].free(fmeta->dset); + + if (H5O_PLIST[0].free) + ret_value = H5O_PLIST[0].free(fmeta->plist); + + H5FL_FREE(H5O_fphdf5_t, fmeta); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_fphdf5_debug + * Purpose: Prints debugging information for the metadata message. + * + * H5F_t *f IN: pointer to the HDF5 file struct + * const void *mesg IN: Pointer to the source metadata struct + * FILE *stream IN: Pointer to the stream for output data + * int indent IN: Amount to indent information by + * int fwidth IN: Field width (?) + * + * Return: Success: Non-negative + * Failure: Negative + * Programmer: Bill Wendling, 22. August 2002 + * Modifications: + */ +static herr_t +H5O_fphdf5_debug(H5F_t UNUSED *f, const void *mesg, + FILE * stream, int indent, int fwidth) +{ + const H5O_fphdf5_t *fmeta = (const H5O_fphdf5_t *) mesg; + herr_t ret_value = SUCCEED; + unsigned int i; + + FUNC_ENTER_NOAPI(H5O_fphdf5_debug, FAIL); + + /* check args */ + assert(f); + assert(fmeta); + assert(stream); + assert(indent >= 0); + assert(fwidth >= 0); + + HDfprintf(stream, "%*s%-*s\n", indent, "", fwidth, "Metadata:"); + HDfprintf(stream, "%*sOID: 0x", indent + 1, ""); + + for (i = 0; i < sizeof(fmeta->oid); ++i) + HDfprintf(stream, "%02x", fmeta->oid[i]); + + HDfprintf(stream, "\n"); + ret_value = H5O_SDSPACE[0].debug(f, fmeta->sdim, stream, indent + 1, fwidth); + ret_value = H5O_DTYPE[0].debug(f, fmeta->dtype, stream, indent + 1, fwidth); + ret_value = H5O_MTIME[0].debug(f, fmeta->mtime, stream, indent + 1, fwidth); + ret_value = H5O_NAME[0].debug(f, fmeta->group, stream, indent + 1, fwidth); + ret_value = H5O_NAME[0].debug(f, fmeta->dset, stream, indent + 1, fwidth); + ret_value = H5O_PLIST[0].debug(f, fmeta->plist, stream, indent + 1, fwidth); + + HDfprintf(stream, "}\n"); + +done: + FUNC_LEAVE(ret_value); +} + +#endif /* H5_HAVE_FPHDF5 */ diff --git a/src/H5Oplist.c b/src/H5Oplist.c new file mode 100644 index 0000000..a326fba --- /dev/null +++ b/src/H5Oplist.c @@ -0,0 +1,584 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* $Id$ */ + +#define H5P_PACKAGE /* prevent warning from including H5Ppkg.h */ + +#include "H5private.h" /* Generic functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free lists */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Oprivate.h" /* Object headers */ +#include "H5Pprivate.h" /* Property lists */ +#include "H5Ppkg.h" + +#if defined (WIN32) && !defined (__MWERKS__) +#include +#include +#endif + +#define PABLO_MASK H5O_plist_mask + +/* local prototypes */ +static void *H5O_plist_decode(H5F_t *f, const uint8_t *p, H5O_shared_t *sh); +static herr_t H5O_plist_encode(H5F_t *f, uint8_t *p, const void *_mesg); +static size_t H5O_plist_size(H5F_t *f, const void *_mesg); +static herr_t H5O_plist_free(void *_mesg); +static herr_t H5O_plist_debug(H5F_t *f, const void *_mesg, + FILE *stream, int indent, int fwidth); + +/* This message derives from H5O */ +const H5O_class_t H5O_PLIST[1] = {{ + H5O_PLIST_ID, /* message id number */ + "plist", /* message name for debugging */ + sizeof(H5P_genplist_t), /* native message size */ + H5O_plist_decode, /* decode message */ + H5O_plist_encode, /* encode message */ + NULL, /* copy the native value */ + H5O_plist_size, /* size of symbol table entry */ + NULL, /* default reset method */ + H5O_plist_free, /* free method */ + NULL, /* get share method */ + NULL, /* set share method */ + H5O_plist_debug, /* debug the message */ +}}; + +#define H5O_PLIST_VERSION 1 + +/* Is the interface initialized? */ +static int interface_initialize_g = 0; + +#define INTERFACE_INIT NULL + +/* Declare external the free list for hsize_t arrays */ +H5FL_ARR_EXTERN(hsize_t); + +#define UINT_ENCODE(dst, src) \ + if (sizeof(src) == 2) { \ + UINT16ENCODE(dst, src); \ + } else if (sizeof(src) == 4) { \ + UINT32ENCODE(dst, src); \ + } else { \ + /* sizeof(src) == 8 */ \ + UINT64ENCODE(dst, src); \ + } + +#define UINT_DECODE(src, dst) \ + if (sizeof(dst) == 2) { \ + UINT16DECODE(src, dst); \ + } else if (sizeof(dst) == 4) { \ + UINT32DECODE(src, dst); \ + } else { \ + /* sizeof(dst) == 8 */ \ + UINT64DECODE(src, dst); \ + } + +#define INT_ENCODE(dst, src) \ + if (sizeof(src) == 2) { \ + INT16ENCODE(dst, src); \ + } else if (sizeof(src) == 4) { \ + INT32ENCODE(dst, src); \ + } else { \ + /* sizeof(src) == 8 */ \ + INT64ENCODE(dst, src); \ + } + +#define INT_DECODE(src, dst) \ + if (sizeof(dst) == 2) { \ + INT16DECODE(src, dst); \ + } else if (sizeof(dst) == 4) { \ + INT32DECODE(src, dst); \ + } else { \ + /* sizeof(dst) == 8 */ \ + INT64DECODE(src, dst); \ + } + +/* + * Function: H5O_plist_decode + * Purpose: Decode a property list and return a pointer to a memory + * struct with the decoded information. + * + * This function decodes the "raw" form of a serialized + * property list in memory native format. The struct is + * allocated within this function using malloc() and is + * returned to the caller. + * + * H5F_t *f IN: pointer to the HDF5 file struct + * uint8 *p OUT: the raw information buffer + * H5O_shared_t *sh IN: not used; must be NULL + * + * Return: Success: Pointer to the new message in native order + * Failure: NULL + * Programmer: Bill Wendling, 24, September 2002 + * Modifications: + */ +static void * +H5O_plist_decode(H5F_t UNUSED *f, const uint8_t *p, H5O_shared_t UNUSED *sh) +{ + H5P_genplist_t *new_plist = NULL; + H5P_genclass_t *pclass; /* property list class to modify */ + hid_t new_plist_id; /* property list ID of new list created */ + int version; /* message version number */ + unsigned int i, nprops, hashsize; + void *ret_value; + + FUNC_ENTER_NOAPI(H5O_plist_decode, NULL); + + /* check args */ + assert(!f); + assert(p); + assert(!sh); + + /* Version number */ + version = *p++; + + if (version != H5O_PLIST_VERSION) + HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, + "bad version number for property list message"); + + /* Reserved (for what?) */ + ++p; + + /* + * Decode the sizes of the parts of the property list. The sizes + * stored in the file are exact but the parts are aligned on 8-byte + * boundaries. + */ + + /* + * Retrieve the name of the property class with its parent(s). It's a + * regular NULL terminated string. + */ + pclass = H5P_open_class_path(p); + p += HDstrlen(p) + 1; /* + 1 for the NULL */ + + UINT_DECODE(p, nprops); + UINT_DECODE(p, hashsize); + + /* Allocate new property list */ + if ((new_plist = H5MM_calloc(sizeof(H5P_genplist_t) + + ((hashsize - 1) * sizeof(H5P_genprop_t *)))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* Initialize new property list */ + new_plist->pclass = pclass; + new_plist->nprops = 0; /* Initially the plist has the same + number of properties as the class */ + new_plist->class_init = 0; /* Initially, wait until the class + callback finishes to set */ + + /* Create new property list */ + for (i = 0; i < nprops; ++i) { + H5P_genprop_t *tprop; + unsigned str_len; + + /* + * Allocate and initialize the property structure which is going + * to hold the information we're reading in. + */ + if (NULL == (tprop = H5MM_malloc(sizeof(H5P_genprop_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + tprop->create = NULL; + tprop->def_value = NULL; + tprop->set = NULL; + tprop->get = NULL; + tprop->del = NULL; + tprop->copy = NULL; + tprop->close = NULL; + tprop->next = NULL; + + /* Grab the XORed value of the name and get the length of the name */ + UINT_DECODE(p, tprop->xor_val); + UINT_DECODE(p, str_len); + + if (str_len) { + /* If there is a name, allocate space for it and copy */ + if (NULL == (tprop->name = H5MM_malloc(str_len + 1))) { + H5MM_xfree(tprop); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + } + + HDmemcpy(tprop->name, p, str_len + 1); + p += str_len + 1; + } else { + tprop->name = NULL; + ++p; + } + + /* Grab the size of the "value" data */ + UINT_DECODE(p, tprop->size); + + /* Allocate and memcpy the value part of the property. */ + if ((tprop->value = H5MM_malloc(tprop->size)) == NULL) { + H5MM_xfree(tprop->name); + H5MM_xfree(tprop); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + } + + HDmemcpy(tprop->value, p, tprop->size); + p += tprop->size; + + /* Insert the initialized property into the property list */ + if (H5P_add_prop(new_plist->props, new_plist->pclass->hashsize, tprop) < 0) { + H5MM_xfree(tprop->value); + H5MM_xfree(tprop->name); + H5MM_xfree(tprop); + HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, NULL, "Can't insert property into list"); + } + + /* Increment the number of properties in list */ + ++new_plist->nprops; + } + + /* Increment the number of property lists derived from class */ + if (H5P_access_class(new_plist->pclass, H5P_MOD_INC_LST) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, NULL, "Can't increment class ref count"); + + /* Get an atom for the property list */ + if ((new_plist_id = H5I_register(H5I_GENPROP_LST, new_plist)) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, NULL, "unable to atomize property list"); + + /* + * Save the property list ID in the property list struct, for use in + * the property class's 'close' callback + */ + new_plist->plist_id = new_plist_id; + + /* Set the class initialization flag */ + new_plist->class_init = 1; + + /* Set return value */ + ret_value = new_plist; /* success */ + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_plist_encode + * Purpose: Encode a property list and return a pointer to a memory + * struct with the encoded information. + * + * This function encodes the "raw" form of a property list + * into a struct in memory native format. + * + * H5F_t *f IN: pointer to the HDF5 file struct + * uint8 *p OUT: the raw information buffer + * const void *mesg IN: pointer to the metadata to encode + * + * Return: Success: Non-negative + * Failure: Negative + * Programmer: Bill Wendling, 24, September 2002 + * Modifications: + */ +static herr_t +H5O_plist_encode(H5F_t UNUSED *f, uint8_t *p, const void *mesg) +{ + const H5P_genplist_t *plist = (const H5P_genplist_t *)mesg; + herr_t ret_value = SUCCEED; + unsigned int i; + char *class_path; + uint8_t *old = p; + + FUNC_ENTER_NOAPI(H5O_plist_encode, FAIL); + + /* check args */ + assert(!f); + assert(p); + assert(plist); + + /* Version */ + *p++ = H5O_PLIST_VERSION; + + /* Reserved */ + *p++ = '\0'; + + /* + * Encode the sizes of the parts of the property list. The sizes + * stored in the file are exact but the parts are aligned on 8-byte + * boundaries. + */ + + /* + * The class name encoded will look like: + * + * BaseClass/ParentClass/.../DerivedClass + */ + class_path = H5P_get_class_path(plist->pclass); + + if (class_path) { + size_t s = HDstrlen(class_path) + 1; + + HDmemcpy(p, class_path, s); + p += s; + } else { + *p++ = '\0'; + } + + HDfree(class_path); + UINT_ENCODE(p, plist->nprops); + UINT_ENCODE(p, plist->pclass->hashsize); + + for (i = 0; i < plist->pclass->hashsize; ++i) { + H5P_genprop_t *tprop = plist->props[i]; + + /* Walk through the list of properties at each hash location */ + while (tprop) { + const char *n = tprop->name; + + /* + * Copy the meat of the generic property: + * + * 1. The XORed version of the name + * 2. The name of the property + * 3. The size of the property value + * 4. The property value + */ + UINT_ENCODE(p, tprop->xor_val); + + if (n && *n) { + size_t s = HDstrlen(n); + + UINT_ENCODE(p, s); + HDmemcpy(p, n, s + 1); + p += s + 1; + } else { + /* if there isn't a name, put a NULL there */ + UINT_ENCODE(p, 0u); + *p++ = '\0'; + } + + UINT_ENCODE(p, tprop->size); + HDmemcpy(p, tprop->value, tprop->size); + p += tprop->size; + + /* Go to next registered property in class */ + tprop = tprop->next; + } + } + + fprintf(stderr, "number of bytes == %d\n", p - old); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_plist_size + * Purpose: Return the raw message size in bytes. + * + * This function returns the size of the raw elements on + * success. (Not counting the message type or size fields, + * only the data portion of the message). It doesn't take + * into account alignment. + * + * H5F_t *f IN: pointer to the HDF5 file struct + * const void *mesg IN: pointer to the metadata structure + * + * Return: Success: Size of message + * Failure: 0 + * Programmer: Bill Wendling, 24, September 2002 + * Modifications: + */ +static size_t +H5O_plist_size(H5F_t UNUSED *f, const void *mesg) +{ + const H5P_genplist_t *plist = (const H5P_genplist_t *)mesg; + const H5P_genclass_t *pclass; + size_t ret_value; + char *class_path = NULL; + unsigned i; + + FUNC_ENTER_NOAPI(H5O_plist_size, 0); + + /* check args */ + assert(plist); + + ret_value = 2 + /*version info */ + 1; /*reserved */ + + /* + * Loop through the class and its parent(s) to gather the complete + * length of the name. The class name encoded will look like: + * + * DerivedClass/ParentClass/.../BaseClass + */ + pclass = plist->pclass; + + while (pclass) { + if (pclass->name) + ret_value += HDstrlen(pclass->name);/*length of class name */ + + if ((pclass = pclass->parent) != NULL) + ++ret_value; /*separating "/" */ + } + + ++ret_value; /*terminating NULL */ + + class_path = H5P_get_class_path(plist->pclass); + + if (class_path) + ret_value += HDstrlen(class_path) + 1; /*class path */ + else + ++ret_value; + + HDfree(class_path); + ret_value += sizeof(plist->nprops) + /*num properties */ + sizeof(plist->pclass->hashsize); /*hash size */ + + for (i = 0; i < plist->pclass->hashsize; ++i) { + H5P_genprop_t *tprop = plist->props[i]; + + /* Walk through the list of properties at each hash location */ + while (tprop) { + const char *n = tprop->name; + + ret_value += sizeof(tprop->xor_val) + /*xored value */ + sizeof(size_t); /*length of the name */ + + if (n && *n) + ret_value += HDstrlen(n) + 1; /*the name */ + else + ++ret_value; /*the name: NULL */ + + ret_value += sizeof(tprop->size) + /*size of data size */ + tprop->size; /*the data */ + + /* Go to next registered property in class */ + tprop = tprop->next; + } + } + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_plist_free + * Purpose: Free's the property list. + * + * const void *mesg IN: pointer to the property list to free + * + * Return: Success: Non-negative + * Failure: Negative + * Programmer: Bill Wendling, 24, September 2002 + * Modifications: + */ +static herr_t +H5O_plist_free(void *mesg) +{ + H5P_genplist_t *plist = mesg; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5O_plist_free, FAIL); + assert(mesg); + + ret_value = H5P_close(plist); + +done: + FUNC_LEAVE(ret_value); +} + +/* + * Function: H5O_plist_debug + * Purpose: Prints debugging information for the property list message. + * + * H5F_t *f IN: pointer to the HDF5 file struct + * const void *mesg IN: Pointer to the source property list struct + * FILE *stream IN: Pointer to the stream for output data + * int indent IN: Amount to indent information by + * int fwidth IN: Field width (?) + * + * Return: Success: Non-negative + * Failure: Negative + * Programmer: Bill Wendling, 24, September 2002 + * Modifications: + */ +static herr_t +H5O_plist_debug(H5F_t UNUSED *f, const void *mesg, FILE *stream, + int indent, int fwidth) +{ + const H5P_genplist_t *plist = (const H5P_genplist_t *)mesg; + herr_t ret_value = SUCCEED; + unsigned int i; + + FUNC_ENTER_NOAPI(H5O_plist_debug, FAIL); + + /* check args */ + assert(!f); + assert(plist); + assert(stream); + assert(indent >= 0); + assert(fwidth >= 0); + + HDfprintf(stream, "%*s%-*s\n", indent, "", fwidth, "Property List:"); + indent += 2; + HDfprintf(stream, "%*sNumber of properties: %d\n", indent, "", plist->nprops); + HDfprintf(stream, "%*sProperties {\n", indent, ""); + indent += 2; + + for (i = 0; i < plist->pclass->hashsize; ++i) { + H5P_genprop_t *tprop = plist->props[i]; + + HDfprintf(stream, "%*sProperty {\n", indent, ""); + indent += 2; + + /* Walk through the list of properties at each hash location */ + while (tprop) { + register unsigned int j; + + /* + * Copy the meat of the generic property: + * + * 1. The name of the property + * 2. The XORed version of the name + * 3. The size of the property value + * 4. The property value + */ + HDfprintf(stream, "%*sName: ", indent, ""); + + if (tprop->name) + HDfprintf(stream, "%s\n", tprop->name); + else + HDfprintf(stream, "(null)\n"); + + HDfprintf(stream, "%*sXOR Value: %d\n", indent, "", tprop->xor_val); + HDfprintf(stream, "%*sValue Size: %d\n", indent, "", tprop->size); + HDfprintf(stream, "%*sValue: ", indent, ""); + + for (j = 0; j < tprop->size; ++j) + HDfprintf(stream, "%02x ", ((char *)tprop->value)[j]); + + HDfprintf(stream, "\n"); + + /* Go to next registered property in class */ + tprop = tprop->next; + } + + indent -= 2; + HDfprintf(stream, "%*s}\n", indent, ""); + } + + indent -= 2; + HDfprintf(stream, "%*s}\n", indent, ""); + + indent -= 2; + HDfprintf(stream, "%*s}\n", indent, ""); + +done: + FUNC_LEAVE(ret_value); +} diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 365a65f..f1e42ef 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -1,8 +1,18 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + /*------------------------------------------------------------------------- - * Copyright (C) 1997-2001 National Center for Supercomputing Applications - * All rights reserved. - * - *------------------------------------------------------------------------- * * Created: H5Oprivate.h * Aug 5 1997 @@ -25,8 +35,9 @@ #include "H5Fprivate.h" #include "H5Gprivate.h" #include "H5HGprivate.h" -#include "H5Tprivate.h" +#include "H5Rprivate.h" #include "H5Spublic.h" +#include "H5Tprivate.h" #include "H5Zprivate.h" /* @@ -291,6 +302,37 @@ typedef struct H5O_stab_t { haddr_t heap_addr; /*address of name heap */ } H5O_stab_t; +/* + * Generic property list message. + */ +#define H5O_PLIST_ID 0x0012 +H5_DLLVAR const H5O_class_t H5O_PLIST[1]; + +/* operates on an H5P_genplist_t struct */ + +#ifdef H5_HAVE_FPHDF5 +/* + * Flexible parallel message + */ +#define H5O_FPHDF5_ID 0x0013 +H5_DLLVAR const H5O_class_t H5O_FPHDF5[1]; + +struct H5S_simple_t; +struct H5P_genplist_t; + +typedef struct H5O_fphdf5_t { + uint8_t oid[H5R_OBJ_REF_BUF_SIZE]; /* OID of object */ + struct H5S_simple_t *sdim; /* Simple dimensionality structure */ + H5T_t *dtype; /* Datatype structure */ + time_t *mtime; /* Modification time */ + H5O_name_t *group; /* Group name */ + H5O_name_t *dset; /* Dataset name */ + struct H5P_genplist_t *plist; /* Property list of the object */ +} H5O_fphdf5_t; + +/* operates on an H5O_fphdf5_t struct */ +#endif /* H5_HAVE_FPHDF5 */ + /* General message operators */ H5_DLL herr_t H5O_create(H5F_t *f, size_t size_hint, H5G_entry_t *ent/*out*/); -- cgit v0.12