From 19ec99786adba12a7517f633888c3976738135ce Mon Sep 17 00:00:00 2001 From: Robb Matzke Date: Thu, 8 Oct 1998 12:13:14 -0500 Subject: [svn-r745] Changes since 19981002 ---------------------- ./doc/html/H5.format.html ./src/H5HG.c Fixed a bug in the global heap that caused H5HG_read() to write past the end of the buffer in certain cases. ./test/big.c The test is skipped if hdf5 was configured with `--disable-hsizet'. ./src/H5Ofill.c Data type conversions are implemented for the fill value. ./src/H5.c Tracing prints one of H5P_FILE_CREATE, H5P_FILE_ACCESS, H5P_DATASET_CREATE, H5P_DATASET_XFER, or H5P_MOUNT instead of the more cryptic H5I_TEMPLATE_* constants. ./src/H5D.c Removed prototype for H5D_find_name(). ./src/H5I.c The GROUP_MASK and ID_MASK are both calculated from GROUP_BITS instead of being set by hand. We don't use the sign bit of hid_t; all valid hid_t values are positive so we can say things like `if ((file=H5Fopen(...))<0)'. Changed `(int)pow(2.0,x)' to `1< - Object Total Size + Object Data Size @@ -1174,9 +1174,10 @@ - Object Total Size - This is the total size in bytes of the object. It - includes all fields listed in this table. + Object Size This is the size of the the fields + above plus the object data stored for the object. The + actual storage size is rounded up to a multiple of + eight. @@ -3402,7 +3403,7 @@ data-type.
Quincey Koziol
Robb Matzke
-Last modified: Thu Oct 1 10:09:54 EDT 1998 +Last modified: Thu Oct 8 09:34:16 EDT 1998 diff --git a/src/H5.c b/src/H5.c index 4c3b583..5ca82e3 100644 --- a/src/H5.c +++ b/src/H5.c @@ -1769,7 +1769,27 @@ H5_trace (hbool_t returning, const char *func, const char *type, ...) case H5I_TEMPLATE_5: case H5I_TEMPLATE_6: case H5I_TEMPLATE_7: - fprintf (out, "H5I_TEMPLATE_%d",(int)(id_type-H5I_TEMPLATE_0)); + switch (H5Pget_class(id_type)) { + case H5P_FILE_CREATE: + fprintf(out, "H5P_FILE_CREATE"); + break; + case H5P_FILE_ACCESS: + fprintf(out, "H5P_FILE_ACCESS"); + break; + case H5P_DATASET_CREATE: + fprintf(out, "H5P_DATASET_CREATE"); + break; + case H5P_DATASET_XFER: + fprintf(out, "H5P_DATASET_XFER"); + break; + case H5P_MOUNT: + fprintf(out, "H5P_MOUNT"); + break; + default: + fprintf (out, "H5I_TEMPLATE_%d", + (int)(id_type-H5I_TEMPLATE_0)); + break; + } break; case H5I_GROUP: fprintf (out, "H5I_GROUP"); diff --git a/src/H5Dprivate.h b/src/H5Dprivate.h index 4e15bf1..1f23d82 100644 --- a/src/H5Dprivate.h +++ b/src/H5Dprivate.h @@ -77,7 +77,6 @@ herr_t H5D_read (H5D_t *dataset, const H5T_t *mem_type, herr_t H5D_write (H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, const H5S_t *file_space, const H5D_xfer_t *xfer_parms, const void *buf); -hid_t H5D_find_name (hid_t file_id, H5I_type_t UNUSED, const char *name); herr_t H5D_extend (H5D_t *dataset, const hsize_t *size); H5G_entry_t *H5D_entof (H5D_t *dataset); H5T_t *H5D_typeof (H5D_t *dset); diff --git a/src/H5E.c b/src/H5E.c index da16fb5..5123b5e 100644 --- a/src/H5E.c +++ b/src/H5E.c @@ -77,6 +77,7 @@ static const H5E_minor_mesg_t H5E_minor_mesg_g[] = { {H5E_NOTHDF5, "Not an HDF5 file"}, {H5E_BADFILE, "Bad file ID accessed"}, {H5E_TRUNCATED, "File has been truncated"}, + {H5E_MOUNT, "File mount error"}, {H5E_SEEKERROR, "Seek failed"}, {H5E_READERROR, "Read failed"}, {H5E_WRITEERROR, "Write failed"}, diff --git a/src/H5Epublic.h b/src/H5Epublic.h index a31317f..fed1296 100644 --- a/src/H5Epublic.h +++ b/src/H5Epublic.h @@ -100,6 +100,7 @@ typedef enum H5E_minor_t { H5E_NOTHDF5, /*not an HDF5 format file */ H5E_BADFILE, /*bad file ID accessed */ H5E_TRUNCATED, /*file has been truncated */ + H5E_MOUNT, /*file mount error */ /* Generic low-level file I/O errors */ H5E_SEEKERROR, /*seek failed */ diff --git a/src/H5F.c b/src/H5F.c index 937cf5e..fe3dfb6 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -94,6 +94,13 @@ const H5F_create_t H5F_create_dflt = { */ H5F_access_t H5F_access_dflt; +/* + * Define the default mount property list. + */ +const H5F_mprop_t H5F_mount_dflt = { + FALSE, /* Absolute symlinks are wrt mount root */ +}; + /* Interface initialization */ static intn interface_initialize_g = FALSE; #define INTERFACE_INIT H5F_init_interface @@ -1661,6 +1668,394 @@ H5Fclose(hid_t file_id) done: FUNC_LEAVE(ret_value < 0 ? FAIL : SUCCEED); } + + +/*------------------------------------------------------------------------- + * Function: H5F_mount + * + * Purpose: Mount file CHILD onto the group specified by LOC and NAME, + * using mount properties in PLIST. CHILD must not already be + * mouted and must not be a mount ancestor of the mount-point. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Tuesday, October 6, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F_mount(H5G_entry_t *loc, const char *name, H5F_t *child, + const H5F_mprop_t *plist) +{ + H5G_t *mount_point = NULL; /*mount point group */ + H5G_entry_t *mp_ent = NULL; /*mount point symbol table entry*/ + H5F_t *ancestor = NULL; /*ancestor files */ + H5F_t *parent = NULL; /*file containing mount point */ + intn lt, rt, md, cmp; /*binary search indices */ + H5G_entry_t *ent = NULL; /*temporary symbol table entry */ + herr_t ret_value = FAIL; /*return value */ + + FUNC_ENTER(H5F_mount, FAIL); + assert(loc); + assert(name && *name); + assert(child); + assert(plist); + + /* + * Check that the child isn't mounted, that the mount point exists, and + * that the mount wouldn't introduce a cycle in the mount tree. + */ + if (child->mtab.parent) { + HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "file is already mounted"); + } + if (NULL==(mount_point=H5G_open(loc, name))) { + HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point not found"); + } + parent = H5G_fileof(mount_point); + mp_ent = H5G_entof(mount_point); + for (ancestor=parent; ancestor; ancestor=ancestor->mtab.parent) { + if (ancestor==child) { + HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, + "mount would introduce a cycle"); + } + } + + /* + * Use a binary search to locate the position that the child should be + * inserted into the parent mount table. At the end of this paragraph + * `md' will be the index where the child should be inserted. + */ + lt = md = 0; + rt = parent->mtab.nmounts; + cmp = -1; + while (ltmtab.child[md].group); + cmp = H5F_addr_cmp(&(mp_ent->header), &(ent->header)); + if (cmp<0) { + rt = md; + } else if (cmp>0) { + lt = md+1; + } + } + if (cmp>0) md++; + if (!cmp) { + HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, + "mount point is already in use"); + } + + /* Make room in the table */ + if (parent->mtab.nmounts>=parent->mtab.nalloc) { + uintn n = MAX(16, 2*parent->mtab.nalloc); + H5F_mount_t *x = H5MM_realloc(parent->mtab.child, + n*sizeof(parent->mtab.child[0])); + if (!x) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed for mount table"); + } + parent->mtab.child = x; + parent->mtab.nalloc = n; + } + + /* Insert into table */ + HDmemmove(parent->mtab.child+md+1, + parent->mtab.child+md, + (parent->mtab.nmounts-md)*sizeof(parent->mtab.child[0])); + parent->mtab.nmounts++; + parent->mtab.child[md].group = mount_point; + parent->mtab.child[md].file = child; + child->mtab.parent = parent; + ret_value = SUCCEED; + + done: + if (ret_value<0 && mount_point) { + H5G_close(mount_point); + } + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5F_unmount + * + * Purpose: Unmount the child which is mounted at the group specified by + * LOC and NAME or fail if nothing is mounted there. Neither + * file is closed. + * + * Because the mount point is specified by name and opened as a + * group, the H5G_namei() will resolve it to the root of the + * mounted file, not the group where the file is mounted. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Tuesday, October 6, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F_unmount(H5G_entry_t *loc, const char *name) +{ + H5G_t *mounted = NULL; /*mount point group */ + H5G_entry_t *mnt_ent = NULL; /*mounted symbol table entry */ + H5F_t *child = NULL; /*mounted file */ + H5F_t *parent = NULL; /*file where mounted */ + H5G_entry_t *ent = NULL; /*temporary symbol table entry */ + herr_t ret_value = FAIL; /*return value */ + uintn i; /*coutners */ + intn lt, rt, md, cmp; /*binary search indices */ + + FUNC_ENTER(H5F_unmount, FAIL); + assert(loc); + assert(name && *name); + + /* + * Get the mount point, or more precisely the root of the mounted file. + * If we get the root group and the file has a parent in the mount tree, + * then we must have found the mount point. + */ + if (NULL==(mounted=H5G_open(loc, name))) { + HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point not found"); + } + child = H5G_fileof(mounted); + mnt_ent = H5G_entof(mounted); + ent = H5G_entof(child->shared->root_grp); + + if (child->mtab.parent && + H5F_addr_eq(&(mnt_ent->header), &(ent->header))) { + /* + * We've been given the root group of the child. We do a reverse + * lookup in the parent's mount table to find the correct entry. + */ + parent = child->mtab.parent; + for (i=0; imtab.nmounts; i++) { + if (parent->mtab.child[i].file==child) { + /* Unmount the child */ + parent->mtab.nmounts -= 1; + H5G_close(parent->mtab.child[i].group); + child->mtab.parent = NULL; + HDmemmove(parent->mtab.child+i, + parent->mtab.child+i+1, + ((parent->mtab.nmounts-i)* + sizeof(parent->mtab.child[0]))); + ret_value = SUCCEED; + } + } + assert(ret_value>=0); + + } else { + /* + * We've been given the mount point in the parent. We use a binary + * search in the parent to locate the mounted file, if any. + */ + parent = child; /*we guessed wrong*/ + lt = 0; + rt = parent->mtab.nmounts; + cmp = -1; + while (ltmtab.child[md].group); + cmp = H5F_addr_cmp(&(mnt_ent->header), &(ent->header)); + if (cmp<0) { + rt = md; + } else { + lt = md+1; + } + } + if (cmp) { + HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "not a mount point"); + } + + /* Unmount the child */ + parent->mtab.nmounts -= 1; + H5G_close(parent->mtab.child[md].group); + parent->mtab.child[md].file->mtab.parent = NULL; + HDmemmove(parent->mtab.child+md, + parent->mtab.child+md+1, + (parent->mtab.nmounts-md)*sizeof(parent->mtab.child[0])); + ret_value = SUCCEED; + } + + done: + if (mounted) H5G_close(mounted); + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5F_mountpoint + * + * Purpose: If ENT is a mount point then copy the entry for the root + * group of the mounted file into ENT. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Tuesday, October 6, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_mountpoint(H5G_entry_t *find/*in,out*/) +{ + H5F_t *parent = find->file; + intn lt, rt, md, cmp; + H5G_entry_t *ent = NULL; + + FUNC_ENTER(H5F_mountpoint, FAIL); + assert(find); + + /* + * The loop is necessary because we might have file1 mounted at the root + * of file2, which is mounted somewhere in file3. + */ + do { + /* + * Use a binary search to find the potential mount point in the mount + * table for the parent + */ + lt = 0; + rt = parent->mtab.nmounts; + cmp = -1; + while (ltmtab.child[md].group); + cmp = H5F_addr_cmp(&(find->header), &(ent->header)); + if (cmp<0) { + rt = md; + } else { + lt = md+1; + } + } + + /* Copy root info over to ENT */ + if (0==cmp) { + ent = H5G_entof(parent->mtab.child[md].file->shared->root_grp); + *find = *ent; + } + } while (!cmp); + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5Fmount + * + * Purpose: Mount file CHILD_ID onto the group specified by LOC_ID and + * NAME using mount properties PLIST_ID. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Tuesday, October 6, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5Fmount(hid_t loc_id, const char *name, hid_t child_id, hid_t plist_id) +{ + H5G_entry_t *loc = NULL; + const H5F_mprop_t *plist = NULL; + H5F_t *child = NULL; + + FUNC_ENTER(H5Fmount, FAIL); + H5TRACE4("e","isii",loc_id,name,child_id,plist_id); + + /* Check arguments */ + if (NULL==(loc=H5G_loc(loc_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location"); + } + if (!name || !*name) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name"); + } + if (H5I_FILE!=H5I_get_type(child_id) || + NULL==(child=H5I_object(child_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file"); + } + if (H5P_DEFAULT==plist_id) { + plist = &H5F_mount_dflt; + } else if (H5P_MOUNT!=H5P_get_class(plist_id) || + NULL==(plist=H5I_object(plist_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "not a mount property list"); + } + + /* Do the mount */ + if (H5F_mount(loc, name, child, plist)<0) { + HRETURN_ERROR(H5E_FILE, H5E_MOUNT, FAIL, + "unable to mount file"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5Funmount + * + * Purpose: Given a mount point, dissassociate the mount point's file + * from the file mounted there. Do not close either file. + * + * The mount point can either be the group in the parent or the + * root group of the mounted file (both groups have the same + * name). If the mount point was opened before the mount then + * it's the group in the parent, but if it was opened after the + * mount then it's the root group of the child. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Tuesday, October 6, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +hid_t +H5Funmount(hid_t loc_id, const char *name) +{ + H5G_entry_t *loc = NULL; + + FUNC_ENTER(H5Funmount, FAIL); + H5TRACE2("i","is",loc_id,name); + + /* Check args */ + if (NULL==(loc=H5G_loc(loc_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location"); + } + if (!name || !*name) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name"); + } + + /* Unmount */ + if (H5F_unmount(loc, name)<0) { + HRETURN_ERROR(H5E_FILE, H5E_MOUNT, FAIL, + "unable to unmount file"); + } + + FUNC_LEAVE(SUCCEED); +} + /*------------------------------------------------------------------------- * Function: H5F_block_read diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index 7f25090..8f33cc0 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -426,6 +426,25 @@ typedef struct H5F_rdcc_t { struct H5F_rdcc_ent_t **slot; /* Chunk slots, each points to a chunk*/ } H5F_rdcc_t; +/* Mount property list */ +typedef struct H5F_mprop_t { + hbool_t local; /* Are absolute symlinks local to file? */ +} H5F_mprop_t; + +/* A record of the mount table */ +typedef struct H5F_mount_t { + struct H5G_t *group; /* Mount point group held open */ + struct H5F_t *file; /* File mounted at that point */ +} H5F_mount_t; + +/* The mount table */ +typedef struct H5F_mtab_t { + struct H5F_t *parent;/* Parent file */ + uintn nmounts;/* Number of children which are mounted */ + uintn nalloc; /* Number of mount slots allocated */ + H5F_mount_t *child; /* An array of mount records */ +} H5F_mtab_t; + /* * Define the structure to store the file information for HDF5 files. One of * these structures is allocated per file, not per H5Fopen(). @@ -463,6 +482,7 @@ typedef struct H5F_t { struct H5G_cwgstk_t *cwg_stack; /* CWG stack for push/pop functions*/ uintn nopen; /* Number of open object headers*/ hbool_t close_pending; /* File close is pending */ + H5F_mtab_t mtab; /* File mount table */ } H5F_t; #ifdef NOT_YET @@ -509,10 +529,12 @@ struct H5O_efl_t; struct H5O_pline_t; struct H5D_xfer_t; struct H5O_fill_t; +struct H5G_entry_t; /* library variables */ extern const H5F_create_t H5F_create_dflt; extern H5F_access_t H5F_access_dflt; +extern const H5F_mprop_t H5F_mount_dflt; #ifdef HAVE_PARALLEL extern hbool_t H5_mpi_1_metawrite_g; @@ -529,6 +551,7 @@ herr_t H5F_debug(H5F_t *f, const haddr_t *addr, FILE * stream, intn indent, intn fwidth); herr_t H5F_istore_debug(H5F_t *f, const haddr_t *addr, FILE * stream, intn indent, intn fwidth, int ndims); +herr_t H5F_mountpoint(struct H5G_entry_t *find/*in,out*/); /* Functions that operate on array storage */ herr_t H5F_arr_create(H5F_t *f, struct H5O_layout_t *layout /*in,out*/); diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h index d00c1d7..319eeeb 100644 --- a/src/H5Fpublic.h +++ b/src/H5Fpublic.h @@ -85,6 +85,8 @@ herr_t H5Fflush(hid_t object_id); herr_t H5Fclose (hid_t file_id); hid_t H5Fget_create_plist (hid_t file_id); hid_t H5Fget_access_plist (hid_t file_id); +herr_t H5Fmount(hid_t loc, const char *name, hid_t child, hid_t plist); +herr_t H5Funmount(hid_t loc, const char *name); #ifdef __cplusplus } diff --git a/src/H5G.c b/src/H5G.c index 3864dcf..2aa045d 100644 --- a/src/H5G.c +++ b/src/H5G.c @@ -1019,6 +1019,11 @@ H5G_basename(const char *name, size_t *size_p) * FOLLOW_SLINK is false and the last component of the name is a * symbolic link then that link is not followed. At most NLINKS * are followed and the next link generates an error. + * + * Mounted files are handled by calling H5F_mountpoint() after + * each step of the translation. If the input argument to that + * function is a mount point then the argument shall be replaced + * with information about the root group of the mounted file. * * Errors: * @@ -1075,7 +1080,6 @@ H5G_namei(H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/, HDmemset(grp_ent, 0, sizeof(H5G_entry_t)); H5F_addr_undef(&(grp_ent->header)); - /* traverse the name */ while ((name = H5G_component(name, &nchars)) && *name) { if (rest) *rest = name; @@ -1132,6 +1136,7 @@ H5G_namei(H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/, } /* next component */ + H5F_mountpoint(obj_ent/*in,out*/); name += nchars; } if (rest) *rest = name; /*final null */ @@ -1737,10 +1742,11 @@ H5G_insert(H5G_entry_t *loc, const char *name, H5G_entry_t *ent) * Insert the object into a symbol table. */ if (H5O_link(ent, 1) < 0) { - HRETURN_ERROR(H5E_SYM, H5E_LINK, FAIL, "link inc failure"); + HRETURN_ERROR(H5E_SYM, H5E_LINK, FAIL, + "unable to increment hard link count"); } if (H5G_stab_insert(&grp, rest, ent) < 0) { - HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't insert"); + HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to insert name"); } FUNC_LEAVE(SUCCEED); } diff --git a/src/H5Gstab.c b/src/H5Gstab.c index cd71183..2e36135 100644 --- a/src/H5Gstab.c +++ b/src/H5Gstab.c @@ -191,7 +191,10 @@ H5G_stab_insert(H5G_entry_t *grp_ent, const char *name, H5G_entry_t *obj_ent) assert(grp_ent && grp_ent->file); assert(name && *name); assert(obj_ent && obj_ent->file); - assert(grp_ent->file->shared == obj_ent->file->shared); + if (grp_ent->file->shared != obj_ent->file->shared) { + HRETURN_ERROR(H5E_SYM, H5E_LINK, FAIL, + "interfile hard links are not allowed"); + } /* initialize data to pass through B-tree */ if (NULL == H5O_read(grp_ent, H5O_STAB, 0, &stab)) { diff --git a/src/H5HG.c b/src/H5HG.c index b0e4c9d..f3e73bf 100644 --- a/src/H5HG.c +++ b/src/H5HG.c @@ -136,7 +136,7 @@ H5HG_create (H5F_t *f, size_t size) H5F_encode_length (f, p, size); /* The freespace object */ - heap->obj[0].size = size - H5HG_SIZEOF_HDR (f); + heap->obj[0].size = size - H5HG_SIZEOF_HDR(f); heap->obj[0].begin = p; UINT16ENCODE(p, 0); /*object ID*/ UINT16ENCODE(p, 0); /*reference count*/ @@ -294,10 +294,11 @@ H5HG_load (H5F_t *f, const haddr_t *addr, const void __unused__ *udata1, p += 4; /*reserved*/ H5F_decode_length (f, p, heap->obj[idx].size); heap->obj[idx].begin = begin; - p = begin + heap->obj[idx].size; + p = begin + H5HG_ALIGN(heap->obj[idx].size); } } - assert (p==heap->chunk+heap->size); + assert(p==heap->chunk+heap->size); + assert(heap->obj[0].size==H5HG_ALIGN(heap->obj[0].size)); /* * Add the new heap to the CWFS list, removing some other entry if @@ -404,7 +405,9 @@ H5HG_flush (H5F_t *f, hbool_t destroy, const haddr_t *addr, H5HG_heap_t *heap) * * Purpose: Given a heap with enough free space, this function will split * the free space to make a new empty heap object and initialize - * the header. + * the header. SIZE is the exact size of the object data to be + * stored. It will be increased to make room for the object + * header and then rounded up for alignment. * * Return: Success: The heap object ID of the new object. * @@ -422,12 +425,13 @@ H5HG_alloc (H5F_t *f, H5HG_heap_t *heap, int cwfsno, size_t size) { int idx; uint8 *p = NULL; - + size_t need = H5HG_ALIGN(H5HG_SIZEOF_OBJHDR(f) + size); + FUNC_ENTER (H5HG_alloc, FAIL); /* Check args */ assert (heap); - assert (heap->obj[0].size>=size); + assert (heap->obj[0].size>=need); /* * Find an ID for the new object. ID zero is reserved for the free space @@ -449,7 +453,7 @@ H5HG_alloc (H5F_t *f, H5HG_heap_t *heap, int cwfsno, size_t size) H5F_encode_length (f, p, size); /* Fix the free space object */ - if (size==heap->obj[0].size) { + if (need==heap->obj[0].size) { /* * All free space has been exhausted from this collection. Remove the * heap from the CWFS list. @@ -462,13 +466,13 @@ H5HG_alloc (H5F_t *f, H5HG_heap_t *heap, int cwfsno, size_t size) (f->shared->ncwfs-cwfsno)*sizeof(H5HG_heap_t*)); } - } else if (heap->obj[0].size-size >= H5HG_SIZEOF_OBJHDR (f)) { + } else if (heap->obj[0].size-need >= H5HG_SIZEOF_OBJHDR (f)) { /* * Some free space remains and it's larger than a heap object header, * so write the new free heap object header to the heap. */ - heap->obj[0].size -= size; - heap->obj[0].begin += size; + heap->obj[0].size -= need; + heap->obj[0].begin += need; p = heap->obj[0].begin; UINT16ENCODE(p, 0); /*id*/ UINT16ENCODE(p, 0); /*nrefs*/ @@ -480,8 +484,8 @@ H5HG_alloc (H5F_t *f, H5HG_heap_t *heap, int cwfsno, size_t size) * Some free space remains but it's smaller than a heap object header, * so we don't write the header. */ - heap->obj[0].size -= size; - heap->obj[0].begin += size; + heap->obj[0].size -= need; + heap->obj[0].begin += need; } heap->dirty = 1; @@ -566,7 +570,7 @@ H5HG_insert (H5F_t *f, size_t size, void *obj, H5HG_t *hobj/*out*/) } /* Split the free space to make room for the new object */ - idx = H5HG_alloc (f, heap, cwfsno, need); + idx = H5HG_alloc (f, heap, cwfsno, size); assert (idx>0); /* Copy data into the heap */ @@ -683,7 +687,7 @@ H5HG_read (H5F_t *f, H5HG_t *hobj, void *object/*out*/) } assert (hobj->idx>0 && hobj->idxnalloc); assert (heap->obj[hobj->idx].begin); - size = heap->obj[hobj->idx].size - H5HG_SIZEOF_OBJHDR (f); + size = heap->obj[hobj->idx].size; p = heap->obj[hobj->idx].begin + H5HG_SIZEOF_OBJHDR (f); if (!object && NULL==(object = H5MM_malloc (size))) { HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, @@ -788,7 +792,7 @@ H5HG_remove (H5F_t *f, H5HG_t *hobj) { uint8 *p=NULL, *obj_start=NULL; H5HG_heap_t *heap = NULL; - size_t size; + size_t need; intn i; FUNC_ENTER (H5HG_remove, FAIL); @@ -808,29 +812,29 @@ H5HG_remove (H5F_t *f, H5HG_t *hobj) assert (hobj->idx>0 && hobj->idxnalloc); assert (heap->obj[hobj->idx].begin); obj_start = heap->obj[hobj->idx].begin; - size = heap->obj[hobj->idx].size; + need = H5HG_ALIGN(heap->obj[hobj->idx].size); /* Move the new free space to the end of the heap */ for (i=0; inalloc; i++) { if (heap->obj[i].begin > heap->obj[hobj->idx].begin) { - heap->obj[i].begin -= size; + heap->obj[i].begin -= need; } } if (NULL==heap->obj[0].begin) { - heap->obj[0].begin = heap->chunk + (heap->size-size); - heap->obj[0].size = size; + heap->obj[0].begin = heap->chunk + (heap->size-need); + heap->obj[0].size = need; heap->obj[0].nrefs = 0; } else { - heap->obj[0].size += size; + heap->obj[0].size += need; } - HDmemmove (obj_start, obj_start+size, - heap->size-((obj_start+size)-heap->chunk)); + HDmemmove (obj_start, obj_start+need, + heap->size-((obj_start+need)-heap->chunk)); if (heap->obj[0].size>=H5HG_SIZEOF_OBJHDR (f)) { p = heap->obj[0].begin; UINT16ENCODE(p, 0); /*id*/ UINT16ENCODE(p, 0); /*nrefs*/ UINT32ENCODE(p, 0); /*reserved*/ - H5F_encode_length (f, p, size); + H5F_encode_length (f, p, need); } HDmemset (heap->obj+hobj->idx, 0, sizeof(H5HG_obj_t)); heap->dirty = 1; @@ -940,9 +944,11 @@ H5HG_debug(H5F_t *f, const haddr_t *addr, FILE *stream, intn indent, fprintf (stream, "%*s%-*s %d\n", indent+3, "", MIN(fwidth-3, 0), "Reference count:", h->obj[i].nrefs); - fprintf (stream, "%*s%-*s %lu\n", indent+3, "", MIN(fwidth-3, 0), + fprintf (stream, "%*s%-*s %lu/%lu\n", indent+3, "", + MIN(fwidth-3, 0), "Size of object body:", - (unsigned long)(h->obj[i].size)); + (unsigned long)(h->obj[i].size), + (unsigned long)H5HG_ALIGN(h->obj[i].size)); size = h->obj[i].size - H5HG_SIZEOF_OBJHDR (f); p = h->obj[i].begin + H5HG_SIZEOF_OBJHDR (f); for (j=0; j32) */ -#define GROUP_BITS 5 -#define GROUP_MASK 0x1F +/* + * Number of bits to use for Group ID in each atom. Increase if H5I_MAXID + * becomes too large (an assertion would fail in H5I_init_interface). This is + * the only number that must be changed since all other bit field sizes and + * masks are calculated from GROUP_BITS. + */ +#define GROUP_BITS 5 +#define GROUP_MASK ((1<> \ - ((sizeof(hid_t)*8)-GROUP_BITS))&GROUP_MASK)) +#define H5I_GROUP(a) ((H5I_type_t)(((hid_t)(a)>>ID_BITS) & GROUP_MASK)) + #ifdef HASH_SIZE_POWER_2 /* @@ -107,11 +114,11 @@ static herr_t H5I_init_interface(void); /* * Map an ID to a hash location. */ -# define H5I_LOC(a,s) (((hid_t)(a)&ID_MASK)%(s)) +# define H5I_LOC(a,s) (((hid_t)(a)&ID_MASK)%(s)) #endif /* Combine a Group number and an atom index into an atom */ -#define H5I_MAKE(g,i) ((((hid_t)(g)&GROUP_MASK)<H5I_BADID && idH5I_BADID && ret_value #include +#include #include #include @@ -296,7 +297,9 @@ H5O_fill_debug(H5F_t *f, const void *_mesg, FILE *stream, intn indent, * Function: H5O_fill_convert * * Purpose: Convert a fill value from whatever data type it currently has - * to the specified data type. + * to the specified dataset type. The `type' field of the fill + * value struct will be set to NULL to indicate that it has the + * same type as the dataset. * * Return: Success: SUCCEED * @@ -312,6 +315,16 @@ H5O_fill_debug(H5F_t *f, const void *_mesg, FILE *stream, intn indent, herr_t H5O_fill_convert(H5O_fill_t *fill, H5T_t *dset_type) { + H5T_cdata_t *cdata=NULL; /*conversion data */ + H5T_conv_t cfunc=NULL; /*conversion function */ + void *buf=NULL, *bkg=NULL; /*conversion buffers */ + herr_t status; /*conversion status */ + hid_t src_id=-1, dst_id=-1; /*data type identifiers */ + herr_t ret_value=FAIL; /*return value */ +#ifdef H5T_DEBUG + H5_timer_t timer; /*debugging timer */ +#endif + FUNC_ENTER(H5O_fill_convert, FAIL); assert(fill); assert(dset_type); @@ -322,10 +335,69 @@ H5O_fill_convert(H5O_fill_t *fill, H5T_t *dset_type) fill->type = NULL; HRETURN(SUCCEED); } - - - HRETURN_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, - "fill value conversion not supported yet"); - FUNC_LEAVE(SUCCEED); + /* + * Can we convert between source and destination data types? + */ + if (NULL==(cfunc=H5T_find(fill->type, dset_type, H5T_BKG_NO, &cdata))) { + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, + "unable to convert between src and dst data types"); + } + if ((src_id = H5I_register(H5I_DATATYPE, + H5T_copy(fill->type, H5T_COPY_TRANSIENT)))<0 || + (dst_id = H5I_register(H5I_DATATYPE, + H5T_copy(dset_type, H5T_COPY_TRANSIENT)))<0) { + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, + "unable to copy/register data type"); + } + + /* + * Data type conversions are always done in place, so we need a buffer + * that is large enough for both source and destination. + */ + if (H5T_get_size(fill->type)>=H5T_get_size(dset_type)) { + buf = fill->buf; + } else { + if (NULL==(buf=H5MM_malloc(H5T_get_size(dset_type)))) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed for type conversion"); + } + HDmemcpy(buf, fill->buf, H5T_get_size(fill->type)); + } + if (cdata->need_bkg>=H5T_BKG_TEMP && + NULL==(bkg=H5MM_malloc(H5T_get_size(dset_type)))) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed for type conversion"); + } + + /* Do the conversion */ +#ifdef H5T_DEBUG + H5T_timer_begin(&timer, cdata); +#endif + cdata->command = H5T_CONV_CONV; + status = (cfunc)(src_id, dst_id, cdata, 1, buf, bkg); +#ifdef H5T_DEBUG + H5T_timer_end(&timer, cdata, 1); +#endif + if (status<0) { + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, + "data type conversion failed"); + } + + /* Update the fill message */ + if (buf!=fill->buf) { + H5MM_xfree(fill->buf); + fill->buf = buf; + } + H5T_close(fill->type); + fill->type = NULL; + fill->size = H5T_get_size(dset_type); + ret_value = SUCCEED; + + done: + if (src_id>=0) H5I_dec_ref(src_id); + if (dst_id>=0) H5I_dec_ref(dst_id); + if (buf!=fill->buf) H5MM_xfree(buf); + H5MM_xfree(bkg); + FUNC_LEAVE(ret_value); } diff --git a/src/H5P.c b/src/H5P.c index 663f009..d9ee64f 100644 --- a/src/H5P.c +++ b/src/H5P.c @@ -188,6 +188,14 @@ H5Pcreate(H5P_class_t type) HDmemcpy(plist, &H5D_xfer_dflt, sizeof(H5D_xfer_t)); break; + case H5P_MOUNT: + if (NULL==(plist = H5MM_malloc(sizeof(H5F_mprop_t)))) { + HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed"); + } + HDmemcpy(plist, &H5F_mount_dflt, sizeof(H5F_mprop_t)); + break; + default: HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown property list class"); @@ -355,6 +363,10 @@ H5P_close (H5P_class_t type, void *plist) /*nothing to do*/ break; + case H5P_MOUNT: + /*nothing to do*/ + break; + default: HRETURN_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "unknown property list class"); @@ -2712,10 +2724,12 @@ H5Pget_fill_value(hid_t plist_id, hid_t type_id, void *value/*out*/) H5T_conv_t cfunc = NULL; /*conversion function */ void *buf = NULL; /*conversion buffer */ void *bkg = NULL; /*conversion buffer */ - H5_timer_t timer; /*conversion timer */ hid_t src_id = -1; /*source data type id */ herr_t status; herr_t ret_value = FAIL; +#ifdef H5T_DEBUG + H5_timer_t timer; /*conversion timer */ +#endif FUNC_ENTER(H5Pget_fill_value, FAIL); H5TRACE3("e","iix",plist_id,type_id,value); @@ -3150,6 +3164,10 @@ H5P_copy (H5P_class_t type, const void *src) size = sizeof(H5D_xfer_t); break; + case H5P_MOUNT: + size = sizeof(H5F_mprop_t); + break; + default: HRETURN_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "unknown property list class"); @@ -3220,6 +3238,11 @@ H5P_copy (H5P_class_t type, const void *src) break; case H5P_DATASET_XFER: + /* Nothing to do */ + break; + + case H5P_MOUNT: + /* Nothing to do */ break; default: diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index cccd4fd..c59b506 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -27,15 +27,16 @@ #include #include -/* Template classes */ +/* Property list classes */ typedef enum H5P_class_t { H5P_NO_CLASS = -1, /*error return value */ - H5P_FILE_CREATE = 0, /*file creation template */ - H5P_FILE_ACCESS = 1, /*file access template */ - H5P_DATASET_CREATE = 2, /*dataset creation template */ - H5P_DATASET_XFER = 3, /*dataset transfer template */ + H5P_FILE_CREATE = 0, /*file creation properties */ + H5P_FILE_ACCESS = 1, /*file access properties */ + H5P_DATASET_CREATE = 2, /*dataset creation properties */ + H5P_DATASET_XFER = 3, /*dataset transfer properties */ + H5P_MOUNT = 4, /*file mounting properties */ - H5P_NCLASSES = 4 /*this must be last! */ + H5P_NCLASSES = 5 /*this must be last! */ } H5P_class_t; #ifdef __cplusplus diff --git a/test/big.c b/test/big.c index 53240e1..c2c81bf 100644 --- a/test/big.c +++ b/test/big.c @@ -180,12 +180,6 @@ writer (int wrt_n) fflush(stdout); /* - * Make sure that `hsize_t' is large enough to represent the entire data - * space. - */ - assert (sizeof(hsize_t)>4); - - /* * We might be on a machine that has 32-bit files, so create an HDF5 file * which is a family of files. Each member of the family will be 1GB */ @@ -392,6 +386,12 @@ main (void) puts("Test skipped because of quota (file size or num open files)."); exit(0); } + if (sizeof(hsize_t)<=4) { + puts("Test skipped because the hdf5 library was configured with the"); + puts("--disable-hsizet flag in order to work around a compiler bug."); + exit(0); + } + /* Set the error handler */ H5Eset_auto (display_error_cb, NULL); diff --git a/test/fillval.c b/test/fillval.c index 3880e23..061e9a8 100644 --- a/test/fillval.c +++ b/test/fillval.c @@ -228,10 +228,11 @@ test_getset(void) static int test_create(const char *filename, H5D_layout_t layout) { - hid_t file, space, dcpl, dset; + hid_t file, space, dcpl, dset1, dset2, dset3; hsize_t cur_size[5] = {32, 16, 8, 4, 2}; hsize_t ch_size[5] = {1, 1, 1, 4, 2}; - int fillval = 0x4c70f1cd, fillval_rd=0; + short rd_s, fill_s = 0x1234; + long rd_l, fill_l = 0x4321; char test[256]; if (H5D_CHUNKED==layout) { @@ -242,7 +243,11 @@ test_create(const char *filename, H5D_layout_t layout) printf("%-70s", test); fflush(stdout); - /* Create a file and dataset */ + /* + * Create a file and three datasets. The three datasets test three fill + * conversion paths: small to large, large to small, and no conversion. + * They depend on `short' being smaller than `long'. + */ if ((file=H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT))<0) goto error; if ((space=H5Screate_simple(5, cur_size, cur_size))<0) goto error; @@ -250,33 +255,88 @@ test_create(const char *filename, H5D_layout_t layout) if (H5D_CHUNKED==layout) { if (H5Pset_chunk(dcpl, 5, ch_size)<0) goto error; } + + /* Small to large fill conversion */ #ifndef NO_FILLING - if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fillval)<0) goto error; + if (H5Pset_fill_value(dcpl, H5T_NATIVE_SHORT, &fill_s)<0) goto error; #endif - if ((dset=H5Dcreate(file, "dset", H5T_NATIVE_INT, space, dcpl))<0) + if ((dset1=H5Dcreate(file, "dset1", H5T_NATIVE_LONG, space, dcpl))<0) goto error; - if (H5Dclose(dset)<0) goto error; + + /* Large to small fill conversion */ +#ifndef NO_FILLING + if (H5Pset_fill_value(dcpl, H5T_NATIVE_LONG, &fill_l)<0) goto error; +#endif + if ((dset2=H5Dcreate(file, "dset2", H5T_NATIVE_SHORT, space, dcpl))<0) + goto error; + + /* No conversion */ +#ifndef NO_FILLING + if (H5Pset_fill_value(dcpl, H5T_NATIVE_LONG, &fill_l)<0) goto error; +#endif + if ((dset3=H5Dcreate(file, "dset3", H5T_NATIVE_LONG, space, dcpl))<0) + goto error; + + /* Close everything */ + if (H5Dclose(dset1)<0) goto error; + if (H5Dclose(dset2)<0) goto error; + if (H5Dclose(dset3)<0) goto error; if (H5Sclose(space)<0) goto error; if (H5Pclose(dcpl)<0) goto error; if (H5Fclose(file)<0) goto error; - /* Open the file and get the dataset fill value */ + /* Open the file and get the dataset fill value from each dataset */ if ((file=H5Fopen(FILE_NAME_1, H5F_ACC_RDONLY, H5P_DEFAULT))<0) goto error; - if ((dset=H5Dopen(file, "dset"))<0) goto error; - if ((dcpl=H5Dget_create_plist(dset))<0) goto error; + + /* Large to small conversion */ + if ((dset1=H5Dopen(file, "dset1"))<0) goto error; + if ((dcpl=H5Dget_create_plist(dset1))<0) goto error; + if (H5Dclose(dset1)<0) goto error; #ifndef NO_FILLING - if (H5Pget_fill_value(dcpl, H5T_NATIVE_INT, &fillval_rd)<0) goto error; - if (fillval_rd!=fillval) { + if (H5Pget_fill_value(dcpl, H5T_NATIVE_SHORT, &rd_s)<0) goto error; + if (rd_s!=fill_s) { puts("*FAILED*"); puts(" Got a different fill value than what was set."); + printf(" Got %d, set %d\n", rd_s, fill_s); goto error; } #endif if (H5Pclose(dcpl)<0) goto error; - if (H5Dclose(dset)<0) goto error; - if (H5Fclose(file)<0) goto error; + /* Small to large conversion */ + if ((dset2=H5Dopen(file, "dset2"))<0) goto error; + if ((dcpl=H5Dget_create_plist(dset2))<0) goto error; + if (H5Dclose(dset2)<0) goto error; +#ifndef NO_FILLING + if (H5Pget_fill_value(dcpl, H5T_NATIVE_LONG, &rd_l)<0) goto error; + if (rd_l!=fill_l) { + puts("*FAILED*"); + puts(" Got a different fill value than what was set."); + printf(" Got %ld, set %ld\n", rd_l, fill_l); + goto error; + } +#endif + if (H5Pclose(dcpl)<0) goto error; + + /* No conversion */ + if ((dset3=H5Dopen(file, "dset3"))<0) goto error; + if ((dcpl=H5Dget_create_plist(dset3))<0) goto error; + if (H5Dclose(dset3)<0) goto error; +#ifndef NO_FILLING + if (H5Pget_fill_value(dcpl, H5T_NATIVE_LONG, &rd_l)<0) goto error; + if (rd_l!=fill_l) { + puts("*FAILED*"); + puts(" Got a different fill value than what was set."); + printf(" Got %ld, set %ld\n", rd_l, fill_l); + goto error; + } +#endif + if (H5Pclose(dcpl)<0) goto error; + + + + if (H5Fclose(file)<0) goto error; puts(" PASSED"); return 0; @@ -284,7 +344,9 @@ test_create(const char *filename, H5D_layout_t layout) H5E_BEGIN_TRY { H5Pclose(dcpl); H5Sclose(space); - H5Dclose(dset); + H5Dclose(dset1); + H5Dclose(dset2); + H5Dclose(dset3); H5Fclose(file); } H5E_END_TRY; return 1; -- cgit v0.12