summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/H5FP.c284
-rw-r--r--src/H5FPclient.c501
-rw-r--r--src/H5FPprivate.h201
-rw-r--r--src/H5FPpublic.h22
-rw-r--r--src/H5FPserver.c1358
-rw-r--r--src/H5Ofphdf5.c519
-rw-r--r--src/H5Oplist.c584
-rw-r--r--src/H5Oprivate.h52
8 files changed, 3516 insertions, 5 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.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"
+
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.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 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 <sys/types.h>
+#include <sys/timeb.h>
+#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 <sys/types.h>
+#include <sys/timeb.h>
+#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*/);