diff --git a/h5_test/tst_h_dimscales2.c b/h5_test/tst_h_dimscales2.c index 634d80902..11082d979 100644 --- a/h5_test/tst_h_dimscales2.c +++ b/h5_test/tst_h_dimscales2.c @@ -20,11 +20,6 @@ #define DIMSCALE_LABEL "dimscale_label" #define STR_LEN 255 -/* typedef struct { */ -/* unsigned long fileno; /\*file number *\/ */ -/* haddr_t objno; /\*object number *\/ */ -/* } HDF5_OBJID_T; */ - herr_t alien_visitor(hid_t did, unsigned dim, hid_t dsid, void *visitor_data) { @@ -37,34 +32,21 @@ herr_t alien_visitor(hid_t did, unsigned dim, hid_t dsid, if (H5Iget_name(did, name1, STR_LEN) < 0) ERR; if (strcmp(&name1[1], VAR1_NAME)) ERR; - /*printf("visiting did 0x%x dim %d dsid 0x%x name of did %s \n", - did, dim, dsid, name1);*/ - /* Get more info on the dimscale object.*/ if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0) ERR; objid->fileno[0] = statbuf.fileno[0]; objid->objno[0] = statbuf.objno[0]; objid->fileno[1] = statbuf.fileno[1]; objid->objno[1] = statbuf.objno[1]; - /*printf("for dsid: statbuf.fileno = %d statbuf.objno = %d\n", - statbuf.fileno, statbuf.objno);*/ - if (H5Gget_objinfo(did, ".", 1, &statbuf) < 0) ERR; - /*printf("for did: statbuf.fileno = %d statbuf.objno = %d\n", - statbuf.fileno, statbuf.objno);*/ return 0; } herr_t alien_visitor2(hid_t did, unsigned dim, hid_t dsid, void *visitor_data) { - char name1[STR_LEN]; H5G_stat_t statbuf; HDF5_OBJID_T *objid = visitor_data; - if (H5Iget_name(did, name1, STR_LEN) < 0) ERR; - /*printf("visiting did 0x%x dim %d dsid 0x%x name of did %s \n", - did, dim, dsid, name1); */ - /* Get obj id of the dimscale object. THis will be used later to * match dimensions to dimscales. */ if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0) ERR; @@ -145,9 +127,6 @@ main() if ((obj_class = H5Gget_objtype_by_idx(fileid, i)) < 0) ERR; if (H5Gget_objname_by_idx(fileid, i, obj_name, STR_LEN) < 0) ERR; - /*printf("\nEncountered: HDF5 object obj_class %d obj_name %s\n", - obj_class, obj_name);*/ - /* Deal with object based on its obj_class. */ switch(obj_class) { @@ -179,9 +158,6 @@ main() dimscale_obj.objno[0] = statbuf.objno[0]; dimscale_obj.fileno[1] = statbuf.fileno[1]; dimscale_obj.objno[1] = statbuf.objno[1]; - /*printf("statbuf.fileno = %d statbuf.objno = %d\n", - statbuf.fileno, statbuf.objno);*/ - } else { @@ -193,8 +169,6 @@ main() /* Go through all dimscales for this var and learn about them. */ if (H5DSiterate_scales(datasetid, 0, NULL, alien_visitor, &vars_dimscale_obj) < 0) ERR; - /*printf("vars_dimscale_obj.fileno = %d vars_dimscale_obj.objno = %d\n", - vars_dimscale_obj.fileno, vars_dimscale_obj.objno);*/ if (vars_dimscale_obj.fileno[0] != dimscale_obj.fileno[0] || vars_dimscale_obj.objno[0] != dimscale_obj.objno[0] || vars_dimscale_obj.fileno[1] != dimscale_obj.fileno[1] || @@ -202,8 +176,6 @@ main() /* There's also a label for dimension 0. */ if (H5DSget_label(datasetid, 0, label, STR_LEN) < 0) ERR; - - /*printf("found non-scale dataset %s, label %s\n", obj_name, label);*/ } if (H5Dclose(datasetid) < 0) ERR; break; @@ -304,9 +276,6 @@ main() if ((obj_class = H5Gget_objtype_by_idx(fileid, i)) < 0) ERR; if (H5Gget_objname_by_idx(fileid, i, obj_name, STR_LEN) < 0) ERR; -/* printf("\nEncountered: HDF5 object obj_class %d obj_name %s\n", */ -/* obj_class, obj_name); */ - /* Deal with object based on its obj_class. */ switch(obj_class) { @@ -333,9 +302,6 @@ main() dimscale_obj[dimscale_cnt].objno[0] = statbuf.objno[0]; dimscale_obj[dimscale_cnt].fileno[1] = statbuf.fileno[1]; dimscale_obj[dimscale_cnt].objno[1] = statbuf.objno[1]; -/* printf("dimscale_obj[%d].fileno = %d dimscale_obj[%d].objno = %d\n", */ -/* dimscale_cnt, dimscale_obj[dimscale_cnt].fileno, dimscale_cnt, */ -/* dimscale_obj[dimscale_cnt].objno); */ dimscale_cnt++; } else @@ -791,9 +757,6 @@ main() if ((obj_class = H5Gget_objtype_by_idx(fileid, i)) < 0) ERR; if (H5Gget_objname_by_idx(fileid, i, obj_name, STR_LEN) < 0) ERR; - /* printf("\nEncountered: HDF5 object obj_class %d obj_name %s\n", */ -/* obj_class, obj_name); */ - /* Deal with object based on its obj_class. */ switch(obj_class) { @@ -819,9 +782,6 @@ main() dimscale_obj[dimscale_cnt].objno[0] = statbuf.objno[0]; dimscale_obj[dimscale_cnt].fileno[1] = statbuf.fileno[1]; dimscale_obj[dimscale_cnt].objno[1] = statbuf.objno[1]; - /* printf("dimscale_obj[%d].fileno = %d dimscale_obj[%d].objno = %d\n", */ -/* dimscale_cnt, dimscale_obj[dimscale_cnt].fileno, dimscale_cnt, */ -/* dimscale_obj[dimscale_cnt].objno); */ dimscale_cnt++; } else @@ -982,9 +942,6 @@ main() if ((obj_class = H5Gget_objtype_by_idx(fileid, i)) < 0) ERR; if (H5Gget_objname_by_idx(fileid, i, obj_name, STR_LEN) < 0) ERR; - /* printf("\nEncountered: HDF5 object obj_class %d obj_name %s\n", */ -/* obj_class, obj_name); */ - /* Deal with object based on its obj_class. */ switch(obj_class) { @@ -1010,9 +967,6 @@ main() dimscale_obj[dimscale_cnt].objno[0] = statbuf.objno[0]; dimscale_obj[dimscale_cnt].fileno[1] = statbuf.fileno[1]; dimscale_obj[dimscale_cnt].objno[1] = statbuf.objno[1]; - /* printf("dimscale_obj[%d].fileno = %d dimscale_obj[%d].objno = %d\n", */ -/* dimscale_cnt, dimscale_obj[dimscale_cnt].fileno, dimscale_cnt, */ -/* dimscale_obj[dimscale_cnt].objno); */ dimscale_cnt++; } else diff --git a/h5_test/tst_h_dimscales3.c b/h5_test/tst_h_dimscales3.c index 6485807ff..97867d957 100644 --- a/h5_test/tst_h_dimscales3.c +++ b/h5_test/tst_h_dimscales3.c @@ -23,11 +23,6 @@ #define DIMSCALE_LABEL "dimscale_label" #define STR_LEN 255 -/* typedef struct { */ -/* unsigned long fileno; /\*file number *\/ */ -/* haddr_t objno; /\*object number *\/ */ -/* } HDF5_OBJID_T; */ - herr_t alien_visitor(hid_t did, unsigned dim, hid_t dsid, void *visitor_data) { @@ -40,34 +35,21 @@ herr_t alien_visitor(hid_t did, unsigned dim, hid_t dsid, if (H5Iget_name(did, name1, STR_LEN) < 0) ERR; if (strcmp(&name1[1], VAR1_NAME)) ERR; - /*printf("visiting did 0x%x dim %d dsid 0x%x name of did %s \n", - did, dim, dsid, name1);*/ - /* Get more info on the dimscale object.*/ if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0) ERR; objid->fileno[0] = statbuf.fileno[0]; objid->objno[0] = statbuf.objno[0]; objid->fileno[1] = statbuf.fileno[1]; objid->objno[1] = statbuf.objno[1]; - /*printf("for dsid: statbuf.fileno = %d statbuf.objno = %d\n", - statbuf.fileno, statbuf.objno);*/ - if (H5Gget_objinfo(did, ".", 1, &statbuf) < 0) ERR; - /*printf("for did: statbuf.fileno = %d statbuf.objno = %d\n", - statbuf.fileno, statbuf.objno);*/ return 0; } herr_t alien_visitor2(hid_t did, unsigned dim, hid_t dsid, void *visitor_data) { - char name1[STR_LEN]; H5G_stat_t statbuf; HDF5_OBJID_T *objid = visitor_data; - if (H5Iget_name(did, name1, STR_LEN) < 0) ERR; - /*printf("visiting did 0x%x dim %d dsid 0x%x name of did %s \n", - did, dim, dsid, name1); */ - /* Get obj id of the dimscale object. THis will be used later to * match dimensions to dimscales. */ if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0) ERR; @@ -144,9 +126,6 @@ main() if ((obj_class = H5Gget_objtype_by_idx(fileid, i)) < 0) ERR; if (H5Gget_objname_by_idx(fileid, i, obj_name, STR_LEN) < 0) ERR; - /*printf("\nEncountered: HDF5 object obj_class %d obj_name %s\n", - obj_class, obj_name);*/ - /* Deal with object based on its obj_class. */ switch(obj_class) { @@ -178,9 +157,6 @@ main() dimscale_obj.objno[0] = statbuf.objno[0]; dimscale_obj.fileno[1] = statbuf.fileno[1]; dimscale_obj.objno[1] = statbuf.objno[1]; - /*printf("statbuf.fileno = %d statbuf.objno = %d\n", - statbuf.fileno, statbuf.objno);*/ - } else { @@ -192,8 +168,6 @@ main() /* Go through all dimscales for this var and learn about them. */ if (H5DSiterate_scales(datasetid, 0, NULL, alien_visitor, &vars_dimscale_obj) < 0) ERR; - /*printf("vars_dimscale_obj.fileno = %d vars_dimscale_obj.objno = %d\n", - vars_dimscale_obj.fileno, vars_dimscale_obj.objno);*/ if (vars_dimscale_obj.fileno[0] != dimscale_obj.fileno[0] || vars_dimscale_obj.objno[0] != dimscale_obj.objno[0] || vars_dimscale_obj.fileno[1] != dimscale_obj.fileno[1] || @@ -201,8 +175,6 @@ main() /* There's also a label for dimension 0. */ if (H5DSget_label(datasetid, 0, label, STR_LEN) < 0) ERR; - - /*printf("found non-scale dataset %s, label %s\n", obj_name, label);*/ } if (H5Dclose(datasetid) < 0) ERR; break; diff --git a/h5_test/tst_h_dimscales4.c b/h5_test/tst_h_dimscales4.c index b74bef87a..028078381 100644 --- a/h5_test/tst_h_dimscales4.c +++ b/h5_test/tst_h_dimscales4.c @@ -27,75 +27,25 @@ #define NC_EHDFERR 255 #define DIM_WITHOUT_VARIABLE "This is a netCDF dimension but not a netCDF variable." -/* typedef struct { */ -/* unsigned long fileno; /\*file number *\/ */ -/* haddr_t objno; /\*object number *\/ */ -/* } HDF5_OBJID_T; */ - struct nc_hdf5_link_info { char name[STR_LEN]; H5I_type_t obj_type; }; -#if 0 -static herr_t -visit_link(hid_t g_id, const char *name, const H5L_info_t *info, - void *op_data) -{ - /* A positive return value causes the visit iterator to immediately - * return that positive value, indicating short-circuit - * success. The iterator can be restarted at the next group - * member. */ - int ret = 1; - hid_t id; - - strncpy(((struct nc_hdf5_link_info *)op_data)->name, name, NC_MAX_NAME); - - /* Open this critter. */ - if ((id = H5Oopen_by_addr(g_id, info->u.address)) < 0) - return NC_EHDFERR; - - /* Is this critter a group, type, data, attribute, or what? */ - if ((((struct nc_hdf5_link_info *)op_data)->obj_type = H5Iget_type(id)) < 0) - ret = NC_EHDFERR; - - /* Close the critter to release resouces. */ - if (H5Oclose(id) < 0) - return NC_EHDFERR; - - return ret; -} -#endif - herr_t alien_visitor(hid_t did, unsigned dim, hid_t dsid, void *visitor_data) { -#if 0 - char name1[STR_LEN]; -#endif H5G_stat_t statbuf; HDF5_OBJID_T *objid = visitor_data; - /* This should get "/var1", the name of the dataset that the scale - * is attached to. */ - /*if (H5Iget_name(did, name1, STR_LEN) < 0) ERR;*/ - -/* printf("visiting did 0x%x dim %d dsid 0x%x name of did %s \n", - did, dim, dsid, name1);*/ - /* Get more info on the dimscale object.*/ if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0) ERR; objid->fileno[0] = statbuf.fileno[0]; objid->objno[0] = statbuf.objno[0]; objid->fileno[1] = statbuf.fileno[1]; objid->objno[1] = statbuf.objno[1]; -/* printf("for dsid: statbuf.fileno = %d statbuf.objno = %d\n", - statbuf.fileno, statbuf.objno);*/ - if (H5Gget_objinfo(did, ".", 1, &statbuf) < 0) ERR; -/* printf("for did: statbuf.fileno = %d statbuf.objno = %d\n", - statbuf.fileno, statbuf.objno);*/ return 0; } @@ -105,9 +55,6 @@ main() printf("\n*** Checking HDF5 dimscales detach.\n"); printf("*** Creating a file with two vars with one dimension scale..."); { -#if 0 - hid_t cparmsid; -#endif hid_t fileid, grpid, spaceid, var1_id, var2_id, dimscaleid; hid_t fcpl_id, fapl_id, create_propid, access_propid; hsize_t dims[NDIMS] = {DIM_LEN}; @@ -186,107 +133,6 @@ main() if (H5Dclose(dimscaleid) < 0) ERR; if (H5Gclose(grpid) < 0) ERR; if (H5Fclose(fileid) < 0) ERR; - - /* /\* Now read the file and check it. *\/ */ - /* { */ - /* hid_t fileid, spaceid = 0, datasetid = 0; */ - /* hsize_t num_obj, i; */ - /* int obj_class; */ - /* char obj_name[STR_LEN + 1]; */ - /* char dimscale_name[STR_LEN+1]; */ - /* htri_t is_scale; */ - /* char label[STR_LEN+1]; */ - /* int num_scales; */ - /* hsize_t dims[1], maxdims[1]; */ - /* H5G_stat_t statbuf; */ - /* HDF5_OBJID_T dimscale_obj, vars_dimscale_obj; */ - /* struct nc_hdf5_link_info link_info; */ - /* hsize_t idx = 0; */ - - /* /\* Open the file. *\/ */ - /* if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR; */ - /* if ((grpid = H5Gopen2(fileid, "/", H5P_DEFAULT)) < 0) ERR; */ - - /* /\* Loop through objects in the root group. *\/ */ - /* if (H5Gget_num_objs(fileid, &num_obj) < 0) ERR; */ - /* for (i = 0; i < num_obj; i++) */ - /* { */ - - /* if (H5Literate(grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC, */ - /* &idx, visit_link, (void *)&link_info) < 0) ERR; */ - - /* printf("Encountered: HDF5 object link_info.name %s\n", link_info.name); */ - - /* /\* Deal with object based on its obj_class. *\/ */ - /* switch(link_info.obj_type) */ - /* { */ - /* case H5I_GROUP: */ - /* break; */ - /* case H5I_DATASET: */ - /* /\* Open the dataset. *\/ */ - /* if ((datasetid = H5Dopen1(fileid, link_info.name)) < 0) ERR; */ - - /* if ((spaceid = H5Dget_space(datasetid)) < 0) ERR; */ - /* if (H5Sget_simple_extent_dims(spaceid, dims, maxdims) < 0) ERR; */ - /* if (maxdims[0] != DIM_LEN) ERR; */ - /* if (H5Sclose(spaceid) < 0) ERR; */ - - /* /\* Is this a dimscale? *\/ */ - /* if ((is_scale = H5DSis_scale(datasetid)) < 0) ERR; */ - /* if (is_scale && strcmp(link_info.name, DIMSCALE_NAME)) ERR; */ - /* if (is_scale) */ - /* { */ - /* /\* A dimscale comes with a NAME attribute, in */ - /* * addition to its real name. *\/ */ - /* if (H5DSget_scale_name(datasetid, dimscale_name, STR_LEN) < 0) ERR; */ - /* if (strcmp(dimscale_name, dimscale_wo_var)) ERR; */ - - /* /\* fileno and objno uniquely identify an object and a */ - /* * HDF5 file. *\/ */ - /* if (H5Gget_objinfo(datasetid, ".", 1, &statbuf) < 0) ERR; */ - /* dimscale_obj.fileno[0] = statbuf.fileno[0]; */ - /* dimscale_obj.objno[0] = statbuf.objno[0]; */ - /* dimscale_obj.fileno[1] = statbuf.fileno[1]; */ - /* dimscale_obj.objno[1] = statbuf.objno[1]; */ - /* /\*printf("scale statbuf.fileno = %d statbuf.objno = %d\n", */ - /* statbuf.fileno, statbuf.objno);*\/ */ - - /* } */ - /* else */ - /* { */ - /* /\* Here's how to get the number of scales attached */ - /* * to the dataset's dimension 0. *\/ */ - /* if ((num_scales = H5DSget_num_scales(datasetid, 0)) < 0) ERR; */ - /* if (num_scales != 1) ERR; */ - - /* /\* Go through all dimscales for this var and learn about them. *\/ */ - /* if (H5DSiterate_scales(datasetid, 0, NULL, alien_visitor, */ - /* &vars_dimscale_obj) < 0) ERR; */ - /* /\*printf("vars_dimscale_obj.fileno = %d vars_dimscale_obj.objno = %d\n", */ - /* vars_dimscale_obj.fileno, vars_dimscale_obj.objno);*\/ */ - /* /\* if (vars_dimscale_obj.fileno[0] != dimscale_obj.fileno[0] || *\/ */ - /* /\* vars_dimscale_obj.objno[0] != dimscale_obj.objno[0] || *\/ */ - /* /\* vars_dimscale_obj.fileno[1] != dimscale_obj.fileno[1] || *\/ */ - /* /\* vars_dimscale_obj.objno[1] != dimscale_obj.objno[1]) ERR; *\/ */ - - /* /\* There's also a label for dimension 0. *\/ */ - /* if (H5DSget_label(datasetid, 0, label, STR_LEN) < 0) ERR; */ - - /* /\*printf("found non-scale dataset %s, label %s\n", link_info.name, label);*\/ */ - /* } */ - /* if (H5Dclose(datasetid) < 0) ERR; */ - /* break; */ - /* case H5I_DATATYPE: */ - /* break; */ - /* default: */ - /* printf("Unknown object!"); */ - /* ERR; */ - /* } */ - /* } */ - - /* /\* Close up the shop. *\/ */ - /* if (H5Fclose(fileid) < 0) ERR; */ - /* }*/ } SUMMARIZE_ERR; FINAL_RESULTS; diff --git a/include/nc4internal.h b/include/nc4internal.h index c02932c17..12dd29864 100644 --- a/include/nc4internal.h +++ b/include/nc4internal.h @@ -108,11 +108,9 @@ typedef struct NC_DIM_INFO struct NC_DIM_INFO *next; struct NC_DIM_INFO *prev; hid_t hdf_dimscaleid; - char *old_name; /* only used to rename dim */ - int dirty; - unsigned char coord_var_in_grp; + HDF5_OBJID_T hdf5_objid; struct NC_VAR_INFO *coord_var; /* The coord var, if it exists. */ - int too_long; /* True if len it too big to fit in local size_t. */ + int too_long; /* True if len is too big to fit in local size_t. */ } NC_DIM_INFO_T; typedef struct NC_ATT_INFO @@ -234,7 +232,6 @@ typedef struct NC_GRP_INFO int natts; struct NC_HDF5_FILE_INFO *nc4_info; char *name; - char *old_name; /* need when renaming group */ hid_t hdf_grpid; NC_TYPE_INFO_T *type; } NC_GRP_INFO_T; @@ -292,6 +289,7 @@ int nc4_convert_type(const void *src, void *dest, int dest_long); /* These functions do HDF5 things. */ +int rec_detach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid); int nc4_open_var_grp2(NC_GRP_INFO_T *grp, int varid, hid_t *dataset); int pg_var(NC_PG_T pg, NC *nc, int ncid, int varid, nc_type xtype, int is_long, void *ip); int nc4_pg_var1(NC_PG_T pg, NC *nc, int ncid, int varid, const size_t *indexp, @@ -306,7 +304,7 @@ int nc4_pg_varm(NC_PG_T pg, NC *nc, int ncid, int varid, const size_t *startp, int nc4_rec_match_dimscales(NC_GRP_INFO_T *grp); int nc4_rec_detect_need_to_preserve_dimids(NC_GRP_INFO_T *grp, int *bad_coord_orderp); int nc4_rec_write_metadata(NC_GRP_INFO_T *grp, int bad_coord_order); -int nc4_rec_write_types(NC_GRP_INFO_T *grp); +int nc4_rec_write_groups_types(NC_GRP_INFO_T *grp); int nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5); int nc4_reopen_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var); int nc4_adjust_var_cache(NC_GRP_INFO_T *grp, NC_VAR_INFO_T * var); @@ -321,6 +319,7 @@ NC_GRP_INFO_T *nc4_find_nc_grp(int ncid); NC_GRP_INFO_T *nc4_rec_find_grp(NC_GRP_INFO_T *start_grp, int target_nc_grpid); NC *nc4_find_nc_file(int ncid, NC_HDF5_FILE_INFO_T**); int nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim, NC_GRP_INFO_T **dim_grp); +int nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var); int nc4_find_dim_len(NC_GRP_INFO_T *grp, int dimid, size_t **len); int nc4_find_type(NC_HDF5_FILE_INFO_T *h5, int typeid1, NC_TYPE_INFO_T **type); NC_TYPE_INFO_T *nc4_rec_find_nc_type(NC_GRP_INFO_T *start_grp, hid_t target_nc_typeid); @@ -357,6 +356,10 @@ int nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp); int nc4_enum_member_add(NC_ENUM_MEMBER_INFO_T **list, size_t size, const char *name, const void *value); +/* Break & reform coordinate variables */ +int nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T *dim); +int nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T *dim); + int NC_check_name(const char *name); /* Check and normalize names. */ diff --git a/libsrc4/nc4dim.c b/libsrc4/nc4dim.c index f53fed4c2..bba142607 100644 --- a/libsrc4/nc4dim.c +++ b/libsrc4/nc4dim.c @@ -31,7 +31,7 @@ NC4_inq_unlimdim(int ncid, int *unlimdimidp) int found = 0; int retval; - LOG((2, "called nc_inq_unlimdim")); + LOG((2, "%s: called", __func__)); if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) return retval; @@ -74,7 +74,7 @@ NC4_def_dim(int ncid, const char *name, size_t len, int *idp) char norm_name[NC_MAX_NAME + 1]; int retval = NC_NOERR; - LOG((2, "nc_def_dim: ncid 0x%x name %s len %d", ncid, name, + LOG((2, "%s: ncid 0x%x name %s len %d", __func__, ncid, name, (int)len)); /* Find our global metadata structure. */ @@ -137,7 +137,6 @@ NC4_def_dim(int ncid, const char *name, size_t len, int *idp) return NC_ENOMEM; strcpy(grp->dim->name, norm_name); grp->dim->len = len; - grp->dim->dirty++; if (len == NC_UNLIMITED) grp->dim->unlimited++; @@ -160,7 +159,7 @@ NC4_inq_dimid(int ncid, const char *name, int *idp) int finished = 0; int retval; - LOG((2, "nc_inq_dimid: ncid 0x%x name %s", ncid, name)); + LOG((2, "%s: ncid 0x%x name %s", __func__, ncid, name)); /* Find metadata for this file. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) @@ -204,7 +203,7 @@ NC4_inq_dim(int ncid, int dimid, char *name, size_t *lenp) NC_DIM_INFO_T *dim; int ret = NC_NOERR; - LOG((2, "nc_inq_dim: ncid 0x%x dimid %d", ncid, dimid)); + LOG((2, "%s: ncid 0x%x dimid %d", __func__, ncid, dimid)); /* Find our global metadata structure. */ if ((ret = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) @@ -277,7 +276,7 @@ NC4_rename_dim(int ncid, int dimid, const char *name) if (!name) return NC_EINVAL; - LOG((2, "nc_rename_dim: ncid 0x%x dimid %d name %s", ncid, + LOG((2, "%s: ncid 0x%x dimid %d name %s", __func__, ncid, dimid, name)); /* Find info for this file and group, and set pointer to each. */ @@ -313,33 +312,21 @@ NC4_rename_dim(int ncid, int dimid, const char *name) if (!dim) return NC_EBADDIM; - /* If not in define mode, switch to it, unless the new name is - * shorter. (This is in accordance with the v3 interface.) */ -/* if (!(h5->flags & NC_INDEF) && strlen(name) > strlen(dim->name)) */ -/* { */ -/* if (h5->cmode & NC_CLASSIC_MODEL) */ -/* return NC_ENOTINDEFINE; */ -/* if ((retval = NC4_redef(ncid))) */ -/* return retval; */ -/* } */ - - /* Save the old name, we'll need it to rename this object when we - * sync to HDF5 file. But if there already is an old_name saved, - * just stick with what we've got, since the user might be renaming - * the crap out of this thing, without ever syncing with the - * file. When the sync does take place, we only need the original - * name of the dim, not any of the intermediate ones. If the user - * could just make up his mind, we could all get on to writing some - * data... */ - if (!dim->old_name) + /* Check for renaming dimension w/o variable */ + if (dim->hdf_dimscaleid) { - dim->old_name = dim->name; - dim->name = NULL; - } + /* Sanity check */ + assert(!dim->coord_var); - /* Check if this is a coordinate variable, and if so, mark it dirty */ - if (dim->coord_var) - dim->coord_var->dirty++; + /* Close the HDF5 dataset */ + if (H5Dclose(dim->hdf_dimscaleid) < 0) + return NC_EHDFERR; + dim->hdf_dimscaleid = 0; + + /* Now delete the dataset (it will be recreated later, if necessary) */ + if (H5Gunlink(grp->hdf_grpid, dim->name) < 0) + return NC_EDIMMETA; + } /* Give the dimension its new name in metadata. UTF8 normalization * has been done. */ @@ -349,6 +336,37 @@ NC4_rename_dim(int ncid, int dimid, const char *name) return NC_ENOMEM; strcpy(dim->name, norm_name); + /* Check if dimension was a coordinate variable, but names are different now */ + if (dim->coord_var && strcmp(dim->name, dim->coord_var->name)) + { + /* Break up the coordinate variable */ + if ((retval = nc4_break_coord_var(grp, dim->coord_var, dim))) + return retval; + } + + /* Check if dimension should become a coordinate variable */ + if (!dim->coord_var) + { + NC_VAR_INFO_T *var; + + /* Attempt to find a variable with the same name as the dimension in + * the current group. */ + if ((retval = nc4_find_var(grp, dim->name, &var))) + return retval; + + /* Check if we found a variable and the variable has the dimension in + * index 0. */ + if (var && var->dim[0] == dim) + { + /* Sanity check */ + assert(var->dimids[0] == dim->dimid); + + /* Reform the coordinate variable */ + if ((retval = nc4_reform_coord_var(grp, var, dim))) + return retval; + } + } + return NC_NOERR; } @@ -366,7 +384,7 @@ NC4_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp) int num_unlim = 0; int retval; - LOG((2, "nc_inq_unlimdims: ncid 0x%x", ncid)); + LOG((2, "%s: ncid 0x%x", __func__, ncid)); /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) diff --git a/libsrc4/nc4file.c b/libsrc4/nc4file.c index c99621ede..0f38c1baf 100644 --- a/libsrc4/nc4file.c +++ b/libsrc4/nc4file.c @@ -15,7 +15,7 @@ COPYRIGHT file for copying and redistribution conditions. #include "nc4internal.h" #include "nc4dispatch.h" -#include +#include "H5DSpublic.h" #ifdef USE_HDF4 #include @@ -44,8 +44,7 @@ extern int num_spaces; /* Forward */ static int NC4_enddef(int ncid); -static int nc4_rec_read_types(NC_GRP_INFO_T *grp); -static int nc4_rec_read_vars(NC_GRP_INFO_T *grp); +static int nc4_rec_read_metadata(NC_GRP_INFO_T *grp); static int close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort); #ifdef IGNORE @@ -163,7 +162,7 @@ nc_check_for_hdf(const char *path, int use_parallel, MPI_Comm comm, MPI_Info inf char blob[MAGIC_NUMBER_LEN]; assert(hdf_file && path); - LOG((3, "nc_check_for_hdf: path %s", path)); + LOG((3, "%s: path %s", __func__, path)); /* HDF5 function handles possible user block at beginning of file */ if(H5Fis_hdf5(path)) @@ -237,7 +236,7 @@ nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, else flags = H5F_ACC_TRUNC; - LOG((3, "nc4_create_file: path %s mode 0x%x", path, cmode)); + LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode)); assert(nc && path); /* If this file already exists, and NC_NOCLOBBER is specified, @@ -322,8 +321,8 @@ nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size, nc4_chunk_cache_preemption) < 0) BAIL(NC_EHDFERR); - LOG((4, "nc4_create_file: set HDF raw chunk cache to size %d nelems %d preemption %f", - nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption)); + LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f", + __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption)); #endif /* USE_PARALLEL */ if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) @@ -382,14 +381,6 @@ exit: /*failure exit*/ if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id); if(!nc4_info) return retval; close_netcdf4_file(nc4_info,1); /* treat like abort */ -#if 0 - if (nc4_info->hdfid > 0) H5Fclose(nc4_info->hdfid); - if (nc4_info->root_grp) { - free(nc4_info->root_grp->name); - free(nc4_info->root_grp); - } - free(nc4_info); -#endif return retval; } @@ -419,8 +410,8 @@ NC4_create(const char* path, int cmode, size_t initialsz, int basepe, assert(nc_file && path); - LOG((1, "nc4_create_file: path %s cmode 0x%x comm %d info %d", - path, cmode, comm, info)); + LOG((1, "%s: path %s cmode 0x%x comm %d info %d", + __func__, path, cmode, comm, info)); #ifdef USE_PARALLEL if (mpidata) @@ -487,13 +478,11 @@ NC4_create(const char* path, int cmode, size_t initialsz, int basepe, * which does not have any coordinate data. */ static int read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, - hsize_t scale_size, hsize_t max_scale_size, - int *dim_without_var) + const H5G_stat_t *statbuf, hsize_t scale_size, hsize_t max_scale_size, + NC_DIM_INFO_T **dim) { - /*char *start_of_len;*/ char dimscale_name_att[NC_MAX_NAME + 1] = ""; - hid_t attid = 0; - int max_len; + htri_t attr_exists; int retval; /* Add a dimension for this scale. */ @@ -506,21 +495,28 @@ read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, /* Does this dataset have a hidden attribute that tells us its * dimid? If so, read it. */ - H5E_BEGIN_TRY { + if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0) + return NC_EHDFERR; + if (attr_exists) + { + hid_t attid; + if ((attid = H5Aopen_by_name(datasetid, ".", NC_DIMID_ATT_NAME, H5P_DEFAULT, H5P_DEFAULT)) > 0) { if (H5Aread(attid, H5T_NATIVE_INT, &grp->dim->dimid) < 0) + { + H5Aclose(attid); return NC_EHDFERR; + } if (H5Aclose(attid) < 0) return NC_EHDFERR; } - } H5E_END_TRY; + } - max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name); - if (!(grp->dim->name = malloc((max_len + 1) * sizeof(char)))) + if (!(grp->dim->name = malloc((strlen(obj_name) + 1) * sizeof(char)))) return NC_ENOMEM; - strncpy(grp->dim->name, obj_name, max_len + 1); + strcpy(grp->dim->name, obj_name); if (SIZEOF_SIZE_T < 8 && scale_size > NC_MAX_UINT) { grp->dim->len = NC_MAX_UINT; @@ -528,7 +524,10 @@ read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, } else grp->dim->len = scale_size; - grp->dim->hdf_dimscaleid = datasetid; + grp->dim->hdf5_objid.fileno[0] = statbuf->fileno[0]; + grp->dim->hdf5_objid.fileno[1] = statbuf->fileno[1]; + grp->dim->hdf5_objid.objno[0] = statbuf->objno[0]; + grp->dim->hdf5_objid.objno[1] = statbuf->objno[1]; /* If the dimscale has an unlimited dimension, then this dimension * is unlimited. */ @@ -550,10 +549,16 @@ read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, return retval; grp->dim->len = *lenp; } - (*dim_without_var)++; + + /* Hold open the dataset, since the dimension doesn't have a coordinate variable */ + grp->dim->hdf_dimscaleid = datasetid; + H5Iinc_ref(grp->dim->hdf_dimscaleid); /* Increment number of objects using ID */ } } + /* Set the dimension created */ + *dim = grp->dim; + return NC_NOERR; } @@ -563,6 +568,7 @@ static int read_coord_dimids(NC_VAR_INFO_T *var) { hid_t coord_att_typeid = -1, coord_attid = -1, spaceid = -1; + hssize_t npoints; int ret = 0; /* There is a hidden attribute telling us the ids of the @@ -570,15 +576,20 @@ read_coord_dimids(NC_VAR_INFO_T *var) * variable. Read it. */ if ((coord_attid = H5Aopen_name(var->hdf_datasetid, COORDINATES)) < 0) ret++; if (!ret && (coord_att_typeid = H5Aget_type(coord_attid)) < 0) ret++; - if (!ret && H5Aread(coord_attid, coord_att_typeid, var->dimids) < 0) ret++; - LOG((4, "dimscale %s is multidimensional and has coords", var->name)); /* How many dimensions are there? */ - if ((spaceid = H5Aget_space(coord_attid)) < 0) ret++; + if (!ret && (spaceid = H5Aget_space(coord_attid)) < 0) ret++; #ifdef EXTRA_TESTS num_spaces++; #endif - if (H5Sget_simple_extent_npoints(spaceid) < 0) ret++; + if (!ret && (npoints = H5Sget_simple_extent_npoints(spaceid)) < 0) ret++; + + /* Check that the number of points is the same as the number of dimensions + * for the variable */ + if (npoints != var->ndims) ret++; + + if (!ret && H5Aread(coord_attid, coord_att_typeid, var->dimids) < 0) ret++; + LOG((4, "dimscale %s is multidimensional and has coords", var->name)); /* Set my HDF5 IDs free! */ if (spaceid >= 0 && H5Sclose(spaceid) < 0) ret++; @@ -603,8 +614,6 @@ dimscale_visitor(hid_t did, unsigned dim, hid_t dsid, return -1; /* Pass this information back to caller. */ -/* (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno = statbuf.fileno; - (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno = statbuf.objno;*/ (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[0] = statbuf.fileno[0]; (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[1] = statbuf.fileno[1]; (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[0] = statbuf.objno[0]; @@ -736,9 +745,6 @@ get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid, NC_TYPE_INFO_T *type; htri_t is_str, equal = 0; hid_t class, native_typeid, hdf_typeid; -#if 0 - nc_type my_nc_type = 0; -#endif H5T_order_t order; int endianness; nc_type nc_type_constant[NUM_TYPES] = {NC_CHAR, NC_BYTE, NC_SHORT, NC_INT, NC_FLOAT, @@ -813,12 +819,7 @@ get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid, if ((equal = H5Tequal(native_typeid, native_type_constant[t])) < 0) return NC_EHDFERR; if (equal) - { -#if 0 - my_nc_type = nc_type_constant[t]; -#endif break; - } } /* Find out about endianness. */ @@ -888,9 +889,8 @@ read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att) size_t fixed_size = 0; assert(att->name); - LOG((5, "read_hdf5_att: att->attnum %d att->name %s " - "att->xtype %d att->len %d", att->attnum, att->name, - att->xtype, att->len)); + LOG((5, "%s: att->attnum %d att->name %s att->xtype %d att->len %d", + __func__, att->attnum, att->name, att->xtype, att->len)); /* Get type of attribute in file. */ if ((file_typeid = H5Aget_type(attid)) < 0) @@ -923,12 +923,9 @@ read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att) /* If both att_ndims and att_npoints are zero, then this is a * zero length att. */ if (att_ndims == 0 && att_npoints == 0) - { dims[0] = 0; - } - else if (att->xtype == NC_STRING) { + else if (att->xtype == NC_STRING) dims[0] = att_npoints; - } else if (att->xtype == NC_CHAR) { /* NC_CHAR attributes are written as a scalar in HDF5, of type @@ -1073,11 +1070,11 @@ read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att) * stash it in the group's list of types. Return the netcdf typeid * through a pointer, if caller desires it. */ static int -read_type(NC_GRP_INFO_T *grp, char *type_name) +read_type(NC_GRP_INFO_T *grp, hid_t hdf_typeid, char *type_name) { NC_TYPE_INFO_T *type; H5T_class_t class; - hid_t hdf_typeid, native_typeid = 0; + hid_t native_typeid = 0; int nmembers; hid_t member_hdf_typeid, base_hdf_typeid = 0; char *member_name = NULL; @@ -1091,13 +1088,7 @@ read_type(NC_GRP_INFO_T *grp, char *type_name) assert(grp && type_name); - if (strlen(type_name) > NC_MAX_NAME) - return NC_EBADNAME; - - LOG((4, "read_type: type_name %s grp->name %s", type_name, grp->name)); - - if ((hdf_typeid = H5Topen2(grp->hdf_grpid, type_name, H5P_DEFAULT)) < 0) - return NC_EHDFERR; + LOG((4, "%s: type_name %s grp->name %s", __func__, type_name, grp->name)); /* What is the native type for this platform? */ if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0) @@ -1193,6 +1184,7 @@ read_type(NC_GRP_INFO_T *grp, char *type_name) type->base_nc_type = base_nc_type; type->committed++; type->hdf_typeid = hdf_typeid; + H5Iinc_ref(type->hdf_typeid); /* Increment number of objects using ID */ type->native_typeid = native_typeid; /* Read info about each member of this compound type. */ @@ -1323,9 +1315,11 @@ read_type(NC_GRP_INFO_T *grp, char *type_name) * including the attributes. */ static int read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, - size_t ndims, int is_scale, int num_scales, hid_t access_pid) + size_t ndims, NC_DIM_INFO_T *dim) { NC_VAR_INFO_T *var = NULL; + hid_t access_pid = 0; + int incr_id_rc = 0; /* Whether the dataset ID's ref count has been incremented */ int natts, a, d; NC_ATT_INFO_T *att; @@ -1347,7 +1341,7 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, int f; assert(obj_name && grp); - LOG((4, "read_var: obj_name %s", obj_name)); + LOG((4, "%s: obj_name %s", __func__, obj_name)); /* Add a variable to the end of the group's var list. */ if ((retval = nc4_var_list_add(&grp->var, &var))) @@ -1358,6 +1352,8 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, /* Fill in what we already know. */ var->hdf_datasetid = datasetid; + H5Iinc_ref(var->hdf_datasetid); /* Increment number of objects using ID */ + incr_id_rc++; /* Indicate that we've incremented the ref. count (for errors) */ var->varid = grp->nvars++; var->created++; var->ndims = ndims; @@ -1372,27 +1368,45 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, return NC_ENOMEM; } + /* Get the current chunk cache settings. */ + if ((access_pid = H5Dget_access_plist(datasetid)) < 0) + BAIL(NC_EVARMETA); +#ifdef EXTRA_TESTS + num_plists++; +#endif + /* Learn about current chunk cache settings. */ if ((H5Pget_chunk_cache(access_pid, &(var->chunk_cache_nelems), &(var->chunk_cache_size), &rdcc_w0)) < 0) return NC_EHDFERR; var->chunk_cache_preemption = rdcc_w0; - /* Allocate space for the name. */ - if (!(var->name = malloc((strlen(obj_name) + 1) * sizeof(char)))) - return NC_ENOMEM; - /* Check for a weird case: a non-coordinate variable that has the * same name as a dimension. It's legal in netcdf, and requires * that the HDF5 dataset name be changed. */ - if (!strncmp(obj_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND))) + if (strlen(obj_name) > strlen(NON_COORD_PREPEND) && + !strncmp(obj_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND))) { - if (strlen(obj_name) > NC_MAX_NAME) - return NC_EMAXNAME; + /* Allocate space for the name. */ + if (!(var->name = malloc(((strlen(obj_name) - strlen(NON_COORD_PREPEND))+ 1) * sizeof(char)))) + return NC_ENOMEM; + strcpy(var->name, &obj_name[strlen(NON_COORD_PREPEND)]); + + /* Allocate space for the HDF5 name. */ + if (!(var->hdf5_name = malloc((strlen(obj_name) + 1) * sizeof(char)))) + return NC_ENOMEM; + + strcpy(var->hdf5_name, obj_name); } else + { + /* Allocate space for the name. */ + if (!(var->name = malloc((strlen(obj_name) + 1) * sizeof(char)))) + return NC_ENOMEM; + strcpy(var->name, obj_name); + } /* Find out what filters are applied to this HDF5 dataset, * fletcher32, deflate, and/or shuffle. All other filters are @@ -1415,10 +1429,8 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, for (d = 0; d < var->ndims; d++) var->chunksizes[d] = chunksize[d]; } - else if (layout == H5D_CONTIGUOUS) + else if (layout == H5D_CONTIGUOUS || layout == H5D_COMPACT) var->contiguous++; - else if (layout == H5D_COMPACT) - var->contiguous++; /* The possible values of filter (which is just an int) can be * found in H5Zpublic.h. */ @@ -1497,10 +1509,8 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, else var->no_fill = 1; - /* If it's a scale, mark it as such. If not, allocate space to - * remember whether the dimscale has been attached for each - * dimension. */ - if (is_scale) + /* If it's a scale, mark it as such. */ + if (dim) { assert(ndims); var->dimscale++; @@ -1511,41 +1521,46 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, } else { - var->dimids[0] = grp->dim->dimid; - var->dim[0] = grp->dim; - if(0 == strcmp(var->name, grp->dim->name)) { - grp->dim->coord_var = var; - grp->dim->coord_var_in_grp++; - } /* end if */ + /* sanity check */ + assert(0 == strcmp(var->name, dim->name)); + + var->dimids[0] = dim->dimid; + var->dim[0] = dim; } + dim->coord_var = var; } - else - if (num_scales && ndims && - !(var->dimscale_attached = calloc(ndims, sizeof(int)))) - BAIL(NC_ENOMEM); - - /* If this is not a scale, and has scales, iterate + /* If this is not a scale, but has scales, iterate * through them. (i.e. this is a variable that is not a * coordinate variable) */ - if (!is_scale && num_scales) + else { - /* Store id information allowing us to match hdf5 - * dimscales to netcdf dimensions. */ - if (!(var->dimscale_hdf5_objids = malloc(ndims * sizeof(struct hdf5_objid)))) - BAIL(NC_ENOMEM); - for (d = 0; d < var->ndims; d++) + int num_scales = 0; + + /* Find out how many scales are attached to this + * dataset. H5DSget_num_scales returns an error if there are no + * scales, so convert a negative return value to zero. */ + num_scales = H5DSget_num_scales(datasetid, 0); + if (num_scales < 0) + num_scales = 0; + + if (num_scales && ndims) { - LOG((5, "read_var: about to iterate over scales for dim %d", d)); - if (H5DSiterate_scales(var->hdf_datasetid, d, NULL, dimscale_visitor, - &(var->dimscale_hdf5_objids[d])) < 0) - BAIL(NC_EHDFERR); -/* LOG((5, "read_var: collected scale info for dim %d " - "var %s fileno[0] %d objno[0] %d fileno[1] %d objno[1] %d", - d, var->name, var->dimscale_hdf5_objids[d].fileno[0], - var->dimscale_hdf5_objids[d].objno[0], - var->dimscale_hdf5_objids[d].fileno[1], - var->dimscale_hdf5_objids[d].objno[1]));*/ - var->dimscale_attached[d]++; + /* Allocate space to remember whether the dimscale has been attached + * for each dimension. */ + if (NULL == (var->dimscale_attached = calloc(ndims, sizeof(int)))) + BAIL(NC_ENOMEM); + + /* Store id information allowing us to match hdf5 + * dimscales to netcdf dimensions. */ + if (NULL == (var->dimscale_hdf5_objids = malloc(ndims * sizeof(struct hdf5_objid)))) + BAIL(NC_ENOMEM); + for (d = 0; d < var->ndims; d++) + { + if (H5DSiterate_scales(var->hdf_datasetid, d, NULL, dimscale_visitor, + &(var->dimscale_hdf5_objids[d])) < 0) + BAIL(NC_EHDFERR); + var->dimscale_attached[d]++; + } } } @@ -1566,52 +1581,44 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, BAIL(NC_EATTMETA); if (H5Aget_name(attid, NC_MAX_HDF5_NAME, att_name) < 0) BAIL(NC_EATTMETA); - LOG((4, "read_var: a %d att_name %s", a, att_name)); + LOG((4, "%s:: a %d att_name %s", __func__, a, att_name)); /* Should we ignore this attribute? */ if (strcmp(att_name, REFERENCE_LIST) && strcmp(att_name, CLASS) && strcmp(att_name, DIMENSION_LIST) && strcmp(att_name, NAME) && - strcmp(att_name, COORDINATES)) + strcmp(att_name, COORDINATES) && + strcmp(att_name, NC_DIMID_ATT_NAME)) { - /* Is this the hidden attribute that holds the netCDF - * dimension id for a coordinate variable? */ - if (!strcmp(att_name, NC_DIMID_ATT_NAME)) - { - - } - else - { - /* Add to the end of the list of atts for this var. */ - if ((retval = nc4_att_list_add(&var->att))) - BAIL(retval); - for (att = var->att; att->next; att = att->next) - ; - - /* Fill in the information we know. */ - att->attnum = var->natts++; - if (!(att->name = malloc((strlen(att_name) + 1) * sizeof(char)))) - BAIL(NC_ENOMEM); - strcpy(att->name, att_name); - - /* Read the rest of the info about the att, - * including its values. */ - if ((retval = read_hdf5_att(grp, attid, att))) + /* Add to the end of the list of atts for this var. */ + if ((retval = nc4_att_list_add(&var->att))) + BAIL(retval); + for (att = var->att; att->next; att = att->next) + ; + + /* Fill in the information we know. */ + att->attnum = var->natts++; + if (!(att->name = malloc((strlen(att_name) + 1) * sizeof(char)))) + BAIL(NC_ENOMEM); + strcpy(att->name, att_name); + + /* Read the rest of the info about the att, + * including its values. */ + if ((retval = read_hdf5_att(grp, attid, att))) + { + if (NC_EBADTYPID == retval) { - if (NC_EBADTYPID == retval) - { - if ((retval = nc4_att_list_del(&var->att, att))) - BAIL(retval); - continue; - } - else - BAIL(retval); + if ((retval = nc4_att_list_del(&var->att, att))) + BAIL(retval); + continue; } - - att->created++; - } /* endif not HDF5 att */ - } + else + BAIL(retval); + } + + att->created++; + } /* endif not HDF5 att */ } /* next attribute */ /* Is this a deflated variable with a chunksize greater than the @@ -1620,11 +1627,18 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, BAIL(retval); exit: - if (var && retval) + if (retval) { - if(nc4_var_list_del(&grp->var, var)) - BAIL2(NC_EHDFERR); + if (incr_id_rc && H5Idec_ref(datasetid) < 0) + BAIL2(NC_EHDFERR); + if (var && nc4_var_list_del(&grp->var, var)) + BAIL2(NC_EHDFERR); } + if (access_pid && H5Pclose(access_pid) < 0) + BAIL2(retval); +#ifdef EXTRA_TESTS + num_plists--; +#endif if (propid > 0 && H5Pclose(propid) < 0) BAIL2(NC_EHDFERR); #ifdef EXTRA_TESTS @@ -1705,32 +1719,18 @@ read_grp_atts(NC_GRP_INFO_T *grp) return retval; } -/* This function is called when nc4_rec_read_vars encounters an HDF5 +/* This function is called when nc4_rec_read_metadata encounters an HDF5 * dataset when reading a file. */ static int -read_dataset(NC_GRP_INFO_T *grp, const char *obj_name) +read_dataset(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, + const H5G_stat_t *statbuf) { - hid_t datasetid = 0; - hid_t spaceid = 0, access_pid = 0; + NC_DIM_INFO_T *dim = NULL; /* Dimension created for scales */ + hid_t spaceid = 0; int ndims; - hsize_t *dims = NULL; - hsize_t *max_dims = NULL; int is_scale = 0; - int dim_without_var = 0; - int num_scales = 0; int retval = NC_NOERR; - /* Open this dataset. */ - if ((datasetid = H5Dopen2(grp->hdf_grpid, obj_name, H5P_DEFAULT)) < 0) - BAIL(NC_EVARMETA); - - /* Get the current chunk cache settings. */ - if ((access_pid = H5Dget_access_plist(datasetid)) < 0) - BAIL(NC_EVARMETA); -#ifdef EXTRA_TESTS - num_plists++; -#endif - /* Get the dimension information for this dataset. */ if ((spaceid = H5Dget_space(datasetid)) < 0) BAIL(NC_EHDFERR); @@ -1739,144 +1739,48 @@ read_dataset(NC_GRP_INFO_T *grp, const char *obj_name) #endif if ((ndims = H5Sget_simple_extent_ndims(spaceid)) < 0) BAIL(NC_EHDFERR); - -#if 0 - /* Removed check to remove nc4 dependency on - maximum dimensions. */ - if (ndims > NC_MAX_DIMS) - BAIL(NC_EMAXDIMS); -#endif - - if( (dims = (hsize_t*)malloc(sizeof(hsize_t)*ndims)) == NULL) - BAIL(errno); - if( (max_dims = (hsize_t*)malloc(sizeof(hsize_t)*ndims)) == NULL) - BAIL(errno); - - if (H5Sget_simple_extent_dims(spaceid, dims, max_dims) < 0) - BAIL(NC_EHDFERR); /* Is this a dimscale? */ if ((is_scale = H5DSis_scale(datasetid)) < 0) BAIL(NC_EHDFERR); if (is_scale) { + hsize_t dims[H5S_MAX_RANK]; + hsize_t max_dims[H5S_MAX_RANK]; + + /* Query the scale's size & max. size */ + if (H5Sget_simple_extent_dims(spaceid, dims, max_dims) < 0) + BAIL(NC_EHDFERR); + /* Read the scale information. */ - if ((retval = read_scale(grp, datasetid, obj_name, dims[0], - max_dims[0], &dim_without_var))) + if ((retval = read_scale(grp, datasetid, obj_name, statbuf, dims[0], + max_dims[0], &dim))) BAIL(retval); } - else - { - /* Find out how many scales are attached to this - * dataset. H5DSget_num_scales returns an error if there are no - * scales, so convert a negative return value to zero. */ - num_scales = H5DSget_num_scales(datasetid, 0); - if (num_scales < 0) - num_scales = 0; - } /* Add a var to the linked list, and get its metadata, * unless this is one of those funny dimscales that are a * dimension in netCDF but not a variable. (Spooky!) */ - if (!dim_without_var) - if ((retval = read_var(grp, datasetid, obj_name, ndims, - is_scale, num_scales, access_pid))) + if (NULL == dim || (dim && !dim->hdf_dimscaleid)) + if ((retval = read_var(grp, datasetid, obj_name, ndims, dim))) BAIL(retval); - if (access_pid && H5Pclose(access_pid) < 0) - BAIL2(retval); -#ifdef EXTRA_TESTS - num_plists--; -#endif - if (spaceid && H5Sclose(spaceid) < 0) - BAIL2(retval); -#ifdef EXTRA_TESTS - num_spaces--; -#endif - - if(dims) free(dims); - if(max_dims) free(max_dims); - - return NC_NOERR; - exit: - if (access_pid && H5Pclose(access_pid) < 0) - BAIL2(retval); -#ifdef EXTRA_TESTS - num_plists--; -#endif - if (datasetid && H5Dclose(datasetid) < 0) - BAIL2(retval); if (spaceid && H5Sclose(spaceid) <0) BAIL2(retval); #ifdef EXTRA_TESTS num_spaces--; #endif - if(dims) free(dims); - if(max_dims) free(max_dims); return retval; } -/* Given index, get the HDF5 name of an object and the class of the - * object (group, type, dataset, etc.). This function will try to use - * creation ordering, but if that fails it will use default - * (i.e. alphabetical) ordering. (This is necessary to read existing - * HDF5 archives without creation ordering). */ -/* static int */ -/* get_name_by_idx(NC_HDF5_FILE_INFO_T *h5, hid_t hdf_grpid, int i, */ -/* int *obj_class, char *obj_name) */ -/* { */ -/* H5O_info_t obj_info; */ -/* H5_index_t idx_field = H5_INDEX_CRT_ORDER; */ -/* ssize_t size; */ -/* herr_t res; */ - -/* /\* These HDF5 macros prevent an HDF5 error message when a */ -/* * non-creation-ordered HDF5 file is opened. *\/ */ -/* H5E_BEGIN_TRY { */ -/* res = H5Oget_info_by_idx(hdf_grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, */ -/* i, &obj_info, H5P_DEFAULT); */ -/* } H5E_END_TRY; */ - -/* /\* Creation ordering not available, so make sure this file is */ -/* * opened for read-only access. This is a plain old HDF5 file being */ -/* * read by netCDF-4. *\/ */ -/* if (res < 0) */ -/* { */ -/* if (H5Oget_info_by_idx(hdf_grpid, ".", H5_INDEX_NAME, H5_ITER_INC, */ -/* i, &obj_info, H5P_DEFAULT) < 0) */ -/* return NC_EHDFERR; */ -/* if (!h5->no_write) */ -/* return NC_ECANTWRITE; */ -/* h5->ignore_creationorder = 1; */ -/* idx_field = H5_INDEX_NAME; */ -/* } */ - -/* *obj_class = obj_info.type; */ -/* if ((size = H5Lget_name_by_idx(hdf_grpid, ".", idx_field, H5_ITER_INC, i, */ -/* NULL, 0, H5P_DEFAULT)) < 0) */ -/* return NC_EHDFERR; */ -/* if (size > NC_MAX_NAME) */ -/* return NC_EMAXNAME; */ -/* if (H5Lget_name_by_idx(hdf_grpid, ".", idx_field, H5_ITER_INC, i, */ -/* obj_name, size+1, H5P_DEFAULT) < 0) */ -/* return NC_EHDFERR; */ - -/* LOG((4, "get_name_by_idx: encountered HDF5 object obj_name %s", obj_name)); */ - -/* return NC_NOERR; */ -/* } */ - -#define USE_ITERATE_CODE -#ifdef USE_ITERATE_CODE - static int -nc4_rec_read_types_cb(hid_t grpid, const char *name, const H5L_info_t *info, +nc4_rec_read_metadata_cb(hid_t grpid, const char *name, const H5L_info_t *info, void *_op_data) { hid_t oid=-1; - H5I_type_t otype=-1; + H5G_stat_t statbuf; char oname[NC_MAX_NAME + 1]; NC_GRP_INFO_T *child_grp; NC_GRP_INFO_T *grp = (NC_GRP_INFO_T *) (_op_data); @@ -1886,46 +1790,77 @@ nc4_rec_read_types_cb(hid_t grpid, const char *name, const H5L_info_t *info, if ((oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0) return H5_ITER_ERROR; - if ((otype = H5Iget_type( oid ))<0) { - H5Oclose(oid); - return H5_ITER_ERROR; - } - H5Oclose(oid); - + /* Get more info about the object.*/ + if (H5Gget_objinfo(oid, ".", 1, &statbuf) < 0) + return H5_ITER_ERROR; + strncpy(oname, name, NC_MAX_NAME); - /* Deal with groups and types; ignore the rest. */ - if (otype == H5I_GROUP) + /* Deal with objects. */ + switch(statbuf.type) { - LOG((3, "found group %s", oname)); - if (nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++, - grp, grp->nc4_info->controller, oname, &child_grp)) - return H5_ITER_ERROR; - - if (nc4_rec_read_types(child_grp)) - return H5_ITER_ERROR; - } - else if (otype == H5I_DATATYPE) - { - LOG((3, "found datatype %s", oname)); - if (read_type(grp, oname)) - return H5_ITER_ERROR; + case H5G_GROUP: + LOG((3, "found group %s", oname)); + + /* Add group to file's hierarchy */ + if (nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++, + grp, grp->nc4_info->controller, oname, &child_grp)) + return H5_ITER_ERROR; + + /* Recursively read the child group's metadata */ + if (nc4_rec_read_metadata(child_grp)) + return H5_ITER_ERROR; + break; + + case H5G_DATASET: + { + int retval = NC_NOERR; + + LOG((3, "found dataset %s", oname)); + + /* Learn all about this dataset, which may be a dimscale + * (i.e. dimension metadata), or real data. */ + if ((retval = read_dataset(grp, oid, oname, &statbuf))) + { + /* Allow NC_EBADTYPID to transparently skip over datasets + * which have a datatype that netCDF-4 doesn't undertand + * (currently), but break out of iteration for other + * errors. + */ + if(NC_EBADTYPID != retval) + return H5_ITER_ERROR; + } + } + break; + + case H5G_TYPE: + LOG((3, "found datatype %s", oname)); + if (read_type(grp, oid, oname)) + return H5_ITER_ERROR; + break; + + default: + LOG((0, "Unknown object class %d in %s!", statbuf.type, __func__)); } + /* Close the object */ + if (H5Oclose(oid) < 0) + return H5_ITER_ERROR; + return (H5_ITER_CONT); } static int -nc4_rec_read_types(NC_GRP_INFO_T *grp) +nc4_rec_read_metadata(NC_GRP_INFO_T *grp) { hsize_t idx=0; - int res = 0; + int retval; hid_t pid = 0; unsigned crt_order_flags = 0; - NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; + H5_index_t iter_index; assert(grp && grp->name); - LOG((3, "nc4_rec_read_types: grp->name %s", grp->name)); + LOG((3, "%s: grp->name %s", __func__, grp->name)); /* Open this HDF5 group and retain its grpid. It will remain open * with HDF5 until this file is nc_closed. */ @@ -1946,135 +1881,33 @@ nc4_rec_read_types(NC_GRP_INFO_T *grp) } assert(grp->hdf_grpid > 0); + /* Get the group creation flags, to check for creation ordering */ pid = H5Gget_create_plist(grp->hdf_grpid); H5Pget_link_creation_order(pid, &crt_order_flags); - if(H5Pclose(pid) < 0) + if (H5Pclose(pid) < 0) return NC_EHDFERR; - - crt_order_flags = crt_order_flags & H5_INDEX_CRT_ORDER; - if (crt_order_flags == H5_INDEX_CRT_ORDER) + /* Set the iteration index to use */ + if (crt_order_flags & H5P_CRT_ORDER_TRACKED) + iter_index = H5_INDEX_CRT_ORDER; + else { - res = H5Literate(grp->hdf_grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC, - &idx, nc4_rec_read_types_cb, (void *)grp); - } else - { - /* Without creation ordering, file must be read-only. */ - if (!idx && !h5->no_write) - return NC_ECANTWRITE; - - res = H5Literate(grp->hdf_grpid, H5_INDEX_NAME, H5_ITER_INC, - &idx, nc4_rec_read_types_cb, (void *)grp); + NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; + + /* Without creation ordering, file must be read-only. */ + if (!h5->no_write) + return NC_ECANTWRITE; + + iter_index = H5_INDEX_NAME; } - if (res<0) + + /* Iterate over links in this group, processing all the objects + * and recursively handling the types encountered + */ + if (H5Literate(grp->hdf_grpid, iter_index, H5_ITER_INC, &idx, + nc4_rec_read_metadata_cb, (void *)grp) < 0) return NC_EHDFERR; - return NC_NOERR; /* everything worked! */ -} -static int -nc4_rec_read_vars_cb(hid_t grpid, const char *name, const H5L_info_t *info, - void *_op_data) -{ - hid_t oid=-1; - H5I_type_t otype=-1; - char oname[NC_MAX_NAME + 1]; - NC_GRP_INFO_T *child_grp; - NC_GRP_INFO_T *grp = (NC_GRP_INFO_T *) (_op_data); -#if 0 - NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; -#endif - - memset(oname, 0, NC_MAX_NAME); - /* Open this critter. */ - if ((oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0) - return H5_ITER_ERROR; - - if ((otype = H5Iget_type( oid ))<0) { - H5Oclose(oid); - return H5_ITER_ERROR; - } - H5Oclose(oid); - - strncpy(oname, name, NC_MAX_NAME); - - /* Deal with datasets. */ - switch(otype) - { - case H5I_GROUP: - LOG((3, "re-encountering group %s", oname)); - - /* The NC_GROUP_INFO_T for this group already exists. Find it. */ - for (child_grp = grp->children; child_grp; child_grp = child_grp->next) - if (!strcmp(child_grp->name, oname)) - break; - if (!child_grp) - return H5_ITER_ERROR; - - /* Recursively read the child group's vars. */ - if (nc4_rec_read_vars(child_grp)) - return H5_ITER_ERROR; - break; - case H5I_DATASET: - { - int retval = NC_NOERR; - - LOG((3, "found dataset %s", oname)); - - /* Learn all about this dataset, which may be a dimscale - * (i.e. dimension metadata), or real data. */ - if ((retval = read_dataset(grp, oname))) { - if(NC_EBADTYPID == retval) - return H5_ITER_CONT; - else - return H5_ITER_ERROR; - } - } - break; - case H5I_DATATYPE: - LOG((3, "already handled type %s", oname)); - break; - default: - LOG((0, "Unknown object class %d in nc4_rec_read_vars!", otype)); - } - return (H5_ITER_CONT); -} - -static int -nc4_rec_read_vars(NC_GRP_INFO_T *grp) -{ - hsize_t idx = 0; - int retval = NC_NOERR; - int res = 0; - hid_t pid = 0; - unsigned crt_order_flags = 0; - NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; - - assert(grp && grp->name && grp->hdf_grpid > 0); - LOG((3, "nc4_rec_read_vars: grp->name %s", grp->name)); - - pid = H5Gget_create_plist(grp->hdf_grpid); - H5Pget_link_creation_order(pid, &crt_order_flags); - if(H5Pclose(pid) < 0) - return NC_EHDFERR; - - crt_order_flags = crt_order_flags & H5_INDEX_CRT_ORDER; - - if (crt_order_flags == H5_INDEX_CRT_ORDER) - { - res = H5Literate(grp->hdf_grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC, - &idx, nc4_rec_read_vars_cb, (void *)grp); - } else - { - /* Without creation ordering, file must be read-only. */ - if (!idx && !h5->no_write) - return NC_ECANTWRITE; - - res = H5Literate(grp->hdf_grpid, H5_INDEX_NAME, H5_ITER_INC, - &idx, nc4_rec_read_vars_cb, (void *)grp); - } - if (res<0) - return NC_EHDFERR; - /* Scan the group for global (i.e. group-level) attributes. */ if ((retval = read_grp_atts(grp))) return retval; @@ -2082,243 +1915,6 @@ nc4_rec_read_vars(NC_GRP_INFO_T *grp) return NC_NOERR; /* everything worked! */ } -#else - -/** \internal -This struct is used to pass information back from the callback -function used with H5Literate. -*/ -struct nc_hdf5_link_info -{ - char name[NC_MAX_NAME + 1]; - H5I_type_t obj_type; -}; - -/* This is a callback function for H5Literate(). - -The parameters of this callback function have the following values or -meanings: - -g_id Group that serves as root of the iteration; same value as the -H5Lvisit group_id parameter - -name Name of link, relative to g_id, being examined at current step of -the iteration - -info H5L_info_t struct containing information regarding that link - -op_data User-defined pointer to data required by the application in -processing the link; a pass-through of the op_data pointer provided -with the H5Lvisit function call - -*/ -static herr_t -visit_link(hid_t g_id, const char *name, const H5L_info_t *info, - void *op_data) -{ - /* A positive return value causes the visit iterator to immediately - * return that positive value, indicating short-circuit - * success. The iterator can be restarted at the next group - * member. */ - int ret = 1; - hid_t id; - - /* Get the name, truncating at NC_MAX_NAME. */ - strncpy(((struct nc_hdf5_link_info *)op_data)->name, name, - NC_MAX_NAME); - - /* Open this critter. */ - if ((id = H5Oopen_by_addr(g_id, info->u.address)) < 0) - return NC_EHDFERR; - - /* Is this critter a group, type, data, attribute, or what? */ - if ((((struct nc_hdf5_link_info *)op_data)->obj_type = H5Iget_type(id)) < 0) - ret = NC_EHDFERR; - - /* Close the critter to release resouces. */ - if (H5Oclose(id) < 0) - return NC_EHDFERR; - - return ret; -} - -/* Iterate over one link in the group at a time, returning - * link_info. The creation_ordering and idx pointers keep track of - * whether creation ordering works and the most recently examined - * link. */ -static int -nc4_iterate_link(int *ordering_checked, int *creation_ordering, - hid_t grpid, hsize_t *idx, struct nc_hdf5_link_info *link_info) -{ - int res = 0; - - if (*creation_ordering) - { - /* These HDF5 macros prevent an HDF5 error message when a - * non-creation-ordered HDF5 file is opened. */ - H5E_BEGIN_TRY { - res = H5Literate(grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC, - idx, visit_link, (void *)link_info); - if (res < 0 && *ordering_checked) - return NC_EHDFERR; - } H5E_END_TRY; - } - - if (!*creation_ordering || res < 0) - { - if (H5Literate(grpid, H5_INDEX_NAME, H5_ITER_INC, idx, - visit_link, link_info) != 1) - return NC_EHDFERR; - /* If it didn't work with creation ordering, but did without, - * then we don't have creation ordering. */ - *creation_ordering = 0; - } - - *ordering_checked = 1; - return NC_NOERR; -} - -/* Recursively open groups and read types. */ -int -nc4_rec_read_types(NC_GRP_INFO_T *grp) -{ - hsize_t num_obj, i; - NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; - NC_GRP_INFO_T *child_grp; - hsize_t idx = 0; - struct nc_hdf5_link_info link_info; - int ordering_checked = 0; - int creation_ordering = 1; /* Assume we have it. */ - int retval = NC_NOERR; - - assert(grp && grp->name); - LOG((3, "nc4_rec_read_types: grp->name %s", grp->name)); - - /* Open this HDF5 group and retain its grpid. It will remain open - * with HDF5 until this file is nc_closed. */ - if (!grp->hdf_grpid) - { - if (grp->parent) - { - if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid, - grp->name, H5P_DEFAULT)) < 0) - return NC_EHDFERR; - } - else - { - if ((grp->hdf_grpid = H5Gopen2(grp->nc4_info->hdfid, - "/", H5P_DEFAULT)) < 0) - return NC_EHDFERR; - } - } - assert(grp->hdf_grpid > 0); - - /* How many objects in this group? */ - if (H5Gget_num_objs(grp->hdf_grpid, &num_obj) < 0) - return NC_EVARMETA; - - /* For each object in the group... */ - for (i = 0; i < num_obj; i++) - { - if ((retval = nc4_iterate_link(&ordering_checked, &creation_ordering, - grp->hdf_grpid, &idx, &link_info))) - return retval; - - /* Without creation ordering, file must be read-only. */ - if (!i && !creation_ordering && !h5->no_write) - return NC_ECANTWRITE; - - /* Deal with groups and types; ignore the rest. */ - if (link_info.obj_type == H5I_GROUP) - { - LOG((3, "found group %s", link_info.name)); - if ((retval = nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++, - grp, grp->file, link_info.name, &child_grp))) - return retval; - if ((retval = nc4_rec_read_types(child_grp))) - return retval; - } - else if (link_info.obj_type == H5I_DATATYPE) - { - LOG((3, "found datatype %s", link_info.name)); - if ((retval = read_type(grp, link_info.name))) - return retval; - } - } - - return NC_NOERR; /* everything worked! */ -} - -/* This function recursively reads all the var and attribute metadata - in a HDF5 group, and creates and fills in the netCDF-4 global - metadata structure. */ -int -nc4_rec_read_vars(NC_GRP_INFO_T *grp) -{ - hsize_t num_obj, i; - NC_GRP_INFO_T *child_grp; - struct nc_hdf5_link_info link_info; - hsize_t idx = 0; - int ordering_checked = 0; - int creation_ordering = 1; /* Assume we have it. */ - int retval = NC_NOERR; - - assert(grp && grp->name && grp->hdf_grpid > 0); - LOG((3, "nc4_rec_read_vars: grp->name %s", grp->name)); - - /* How many objects in this group? */ - if (H5Gget_num_objs(grp->hdf_grpid, &num_obj) < 0) - return NC_EVARMETA; - - /* For each object in the group... */ - for (i = 0; i < num_obj; i++) - { - if ((retval = nc4_iterate_link(&ordering_checked, &creation_ordering, - grp->hdf_grpid, &idx, &link_info))) - return retval; - - /* Deal with datasets. */ - switch(link_info.obj_type) - { - case H5I_GROUP: - LOG((3, "re-encountering group %s", link_info.name)); - - /* The NC_GROUP_INFO_T for this group already exists. Find it. */ - for (child_grp = grp->children; child_grp; child_grp = child_grp->next) - if (!strcmp(child_grp->name, link_info.name)) - break; - if (!child_grp) - return NC_EHDFERR; - - /* Recursively read the child group's vars. */ - if ((retval = nc4_rec_read_vars(child_grp))) - return retval; - break; - case H5I_DATASET: - LOG((3, "found dataset %s", link_info.name)); - - /* Learn all about this dataset, which may be a dimscale - * (i.e. dimension metadata), or real data. */ - if ((retval = read_dataset(grp, link_info.name))) - return retval; - break; - case H5I_DATATYPE: - LOG((3, "already handled type %s", link_info.name)); - break; - default: - LOG((0, "Unknown object class %d in nc4_rec_read_vars!", - link_info.obj_type)); - } - } - - /* Scan the group for global (i.e. group-level) attributes. */ - if ((retval = read_grp_atts(grp))) - return retval; - - return NC_NOERR; /* everything worked! */ -} -#endif - /* Open a netcdf-4 file. Things have already been kicked off in * ncfunc.c in nc_open, but here the netCDF-4 part of opening a file * is handled. */ @@ -2336,7 +1932,7 @@ nc4_open_file(const char *path, int mode, MPI_Comm comm, int info_duped = 0; /* Whether the MPI Info object was duplicated */ #endif /* !USE_PARALLEL */ - LOG((3, "nc4_open_file: path %s mode %d", path, mode)); + LOG((3, "%s: path %s mode %d", __func__, path, mode)); assert(path && nc); /* Stop diskless open in its tracks */ if(mode & NC_DISKLESS) @@ -2403,8 +1999,8 @@ nc4_open_file(const char *path, int mode, MPI_Comm comm, if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size, nc4_chunk_cache_preemption) < 0) BAIL(NC_EHDFERR); - LOG((4, "nc4_open_file: set HDF raw chunk cache to size %d nelems %d preemption %f", - nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption)); + LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f", + __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption)); #endif /* USE_PARALLEL */ /* The NetCDF-3.x prototype contains an mode option NC_SHARE for @@ -2421,9 +2017,7 @@ nc4_open_file(const char *path, int mode, MPI_Comm comm, * information may be difficult to resolve here, if, for example, a * dataset of user-defined type is encountered before the * definition of that type. */ - if ((retval = nc4_rec_read_types(nc4_info->root_grp))) - BAIL(retval); - if ((retval = nc4_rec_read_vars(nc4_info->root_grp))) + if ((retval = nc4_rec_read_metadata(nc4_info->root_grp))) BAIL(retval); /* Now figure out which netCDF dims are indicated by the dimscale @@ -2457,14 +2051,6 @@ exit: if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id); if (!nc4_info) return retval; close_netcdf4_file(nc4_info,1); /* treat like abort*/ -#if 0 - if (nc4_info->hdfid > 0) H5Fclose(nc4_info->hdfid); - if (nc4_info->root_grp) { - free(nc4_info->root_grp->name); - free(nc4_info->root_grp); - } - free(nc4_info); -#endif return retval; } @@ -2558,7 +2144,7 @@ nc4_open_hdf4_file(const char *path, int mode, NC *nc) int retval; NC_HDF5_FILE_INFO_T* nc4_info = NULL; - LOG((3, "nc4_open_hdf4_file: path %s mode %d", path, mode)); + LOG((3, "%s: path %s mode %d", __func__, path, mode)); assert(path && nc); /* Must be read-only access to hdf4 files. */ @@ -2840,8 +2426,8 @@ NC4_open(const char *path, int mode, int basepe, size_t *chunksizehintp, assert(nc_file && path); - LOG((1, "nc_open_file: path %s mode %d comm %d info %d", - path, mode, comm, info)); + LOG((1, "%s: path %s mode %d comm %d info %d", + __func__, path, mode, comm, info)); #ifdef USE_PARALLEL if (mpidata) @@ -2936,7 +2522,7 @@ NC4_set_fill(int ncid, int fillmode, int *old_modep) NC *nc; NC_HDF5_FILE_INFO_T* nc4_info; - LOG((2, "nc_set_fill: ncid 0x%x fillmode %d", ncid, fillmode)); + LOG((2, "%s: ncid 0x%x fillmode %d", __func__, ncid, fillmode)); if (!(nc = nc4_find_nc_file(ncid,&nc4_info))) return NC_EBADID; @@ -2974,7 +2560,7 @@ NC4_redef(int ncid) //NC *nc; NC_HDF5_FILE_INFO_T* nc4_info; - LOG((1, "nc_redef: ncid 0x%x", ncid)); + LOG((1, "%s: ncid 0x%x", __func__, ncid)); /* Find this file's metadata. */ if (!(nc4_find_nc_file(ncid,&nc4_info))) @@ -3024,7 +2610,7 @@ static int NC4_enddef(int ncid) NC *nc; NC_HDF5_FILE_INFO_T* nc4_info; - LOG((1, "nc_enddef: ncid 0x%x", ncid)); + LOG((1, "%s: ncid 0x%x", __func__, ncid)); if (!(nc = nc4_find_nc_file(ncid,&nc4_info))) return NC_EBADID; @@ -3055,7 +2641,7 @@ sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5) int retval; assert(h5); - LOG((3, "sync_netcdf4_file")); + LOG((3, "%s", __func__)); /* If we're in define mode, that's an error, for strict nc3 rules, * otherwise, end define mode. */ @@ -3081,7 +2667,8 @@ sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5) if (!(h5->cmode & NC_NOWRITE)) { int bad_coord_order = 0; /* if detected, propagate to all groups to consistently store dimids */ - if ((retval = nc4_rec_write_types(h5->root_grp))) + + if ((retval = nc4_rec_write_groups_types(h5->root_grp))) return retval; if ((retval = nc4_rec_detect_need_to_preserve_dimids(h5->root_grp, &bad_coord_order))) return retval; @@ -3089,11 +2676,8 @@ sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5) return retval; } - H5Fflush(h5->hdfid, H5F_SCOPE_GLOBAL); - - /* Reread all the metadata. */ - /*if ((retval = nc4_rec_read_metadata(grp))) - return retval;*/ + if (H5Fflush(h5->hdfid, H5F_SCOPE_GLOBAL) < 0) + return NC_EHDFERR; return retval; } @@ -3107,7 +2691,7 @@ NC4_sync(int ncid) int retval; NC_HDF5_FILE_INFO_T* nc4_info; - LOG((2, "nc_sync: ncid 0x%x", ncid)); + LOG((2, "%s: ncid 0x%x", __func__, ncid)); if (!(nc = nc4_find_nc_file(ncid,&nc4_info))) return NC_EBADID; @@ -3140,8 +2724,7 @@ close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort) int retval = NC_NOERR; assert(h5 && h5->root_grp); - LOG((3, "close_netcdf4_file: h5->path %s abort %d", - h5->controller->path, abort)); + LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort)); /* According to the docs, always end define mode on close. */ if (h5->flags & NC_INDEF) @@ -3151,19 +2734,19 @@ close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort) * file. */ if (!h5->no_write && !abort) if ((retval = sync_netcdf4_file(h5))) - goto done; + goto exit; /* Delete all the list contents for vars, dims, and atts, in each * group. */ if ((retval = nc4_rec_grp_del(&h5->root_grp, h5->root_grp))) - goto done; + goto exit; /* Close hdf file. */ if (h5->hdf4) { #ifdef USE_HDF4 if (SDend(h5->sdid)) - {retval = NC_EHDFERR; goto done;} + BAIL_QUIET(NC_EHDFERR); #endif /* USE_HDF4 */ } else @@ -3180,10 +2763,11 @@ close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort) if (H5Fclose(h5->hdfid) < 0) { int nobjs; + nobjs = H5Fget_obj_count(h5->hdfid, H5F_OBJ_ALL); /* Apparently we can get an error even when nobjs == 0 */ if(nobjs < 0) { - {retval = NC_EHDFERR; goto done;} + BAIL_QUIET(NC_EHDFERR); } else if(nobjs > 0) { #ifdef LOGGING /* If the close doesn't work, probably there are still some HDF5 @@ -3192,12 +2776,12 @@ close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort) * out. */ LOG((0, "There are %d HDF5 objects open!", nobjs)); #endif - retval = NC_EHDFERR; goto done; + BAIL_QUIET(NC_EHDFERR); } } } -done: +exit: /* Free the nc4_info struct; above code should have reclaimed everything else */ if(h5 != NULL) @@ -3221,7 +2805,7 @@ NC4_abort(int ncid) int retval = NC_NOERR; NC_HDF5_FILE_INFO_T* nc4_info; - LOG((2, "nc_abort: ncid 0x%x", ncid)); + LOG((2, "%s: ncid 0x%x", __func__, ncid)); /* Find metadata for this file. */ if (!(nc = nc4_find_nc_file(ncid,&nc4_info))) @@ -3263,7 +2847,7 @@ NC4_close(int ncid) NC_HDF5_FILE_INFO_T *h5; int retval; - LOG((1, "nc_close: ncid 0x%x", ncid)); + LOG((1, "%s: ncid 0x%x", __func__, ncid)); /* Find our metadata for this file. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) @@ -3301,7 +2885,7 @@ NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp) NC_VAR_INFO_T *var; int retval; - LOG((2, "nc_inq: ncid 0x%x", ncid)); + LOG((2, "%s: ncid 0x%x", __func__, ncid)); /* Find file metadata. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) @@ -3361,7 +2945,7 @@ int nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5) { assert(h5); - LOG((3, "nc4_enddef_netcdf4_file")); + LOG((3, "%s", __func__)); /* If we're not in define mode, return an error. */ if (!(h5->flags & NC_INDEF)) diff --git a/libsrc4/nc4grp.c b/libsrc4/nc4grp.c index 667a06597..a58a3ecc6 100644 --- a/libsrc4/nc4grp.c +++ b/libsrc4/nc4grp.c @@ -23,7 +23,7 @@ NC4_def_grp(int parent_ncid, const char *name, int *new_ncid) char norm_name[NC_MAX_NAME + 1]; int retval; - LOG((2, "nc_def_grp: parent_ncid 0x%x name %s", parent_ncid, name)); + LOG((2, "%s: parent_ncid 0x%x name %s", __func__, parent_ncid, name)); /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_grp_h5(parent_ncid, &grp, &h5))) @@ -98,19 +98,25 @@ NC4_rename_grp(int grpid, const char *name) if ((retval = NC4_redef(grpid))) return retval; - /* Save the old name, we'll need it to rename this object when we - * sync to HDF5 file. But if there already is an old_name saved, - * just stick with what we've got, since the user might be renaming - * the crap out of this thing, without ever syncing with the - * file. When the sync does take place, we only need the original - * name of the grp, not any of the intermediate ones. If the user - * could just make up his mind, we could all get on to writing some - * data... */ - if (!grp->old_name) + /* Rename the group, if it exists in the file */ + if (grp->hdf_grpid) { - if (!(grp->old_name = malloc((strlen(grp->name) + 1) * sizeof(char)))) - return NC_ENOMEM; - strcpy(grp->old_name, grp->name); + /* Close the group */ + if (H5Gclose(grp->hdf_grpid) < 0) + return NC_EHDFERR; + grp->hdf_grpid = 0; + + /* Attempt to rename & re-open the group, if the parent group is open */ + if (grp->parent->hdf_grpid) + { + /* Rename the group */ + if (H5Gmove(grp->parent->hdf_grpid, grp->name, name) < 0) + return NC_EHDFERR; + + /* Reopen the group, with the new name */ + if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid, name, H5P_DEFAULT)) < 0) + return NC_EHDFERR; + } } /* Give the group its new name in metadata. UTF8 normalization diff --git a/libsrc4/nc4hdf.c b/libsrc4/nc4hdf.c index c34494c4a..bc5a8ebbf 100644 --- a/libsrc4/nc4hdf.c +++ b/libsrc4/nc4hdf.c @@ -51,7 +51,7 @@ rec_reattach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid) int retval; assert(grp && grp->name && dimid >= 0 && dimscaleid >= 0); - LOG((3, "rec_reattach_scales: grp->name %s", grp->name)); + LOG((3, "%s: grp->name %s", __func__, grp->name)); /* If there are any child groups, attach dimscale there, if needed. */ for (child_grp = grp->children; child_grp; child_grp = child_grp->next) @@ -63,8 +63,8 @@ rec_reattach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid) for (d = 0; d < var->ndims; d++) if (var->dimids[d] == dimid && !var->dimscale) { - LOG((2, "rec_reattach_scaled: attaching scale for dimid %d to var %s", - var->dimids[d], var->name)); + LOG((2, "%s: attaching scale for dimid %d to var %s", + __func__, var->dimids[d], var->name)); if (var->created) { if (H5DSattach_scale(var->hdf_datasetid, dimscaleid, d) < 0) @@ -82,7 +82,7 @@ rec_reattach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid) * that case, I need to recreate the dim's dimension scale dataset, * and then I need to go to every var in the file which uses that * dimension, and attach the new dimension scale. */ -static int +int rec_detach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid) { NC_VAR_INFO_T *var; @@ -91,66 +91,32 @@ rec_detach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid) int retval; assert(grp && grp->name && dimid >= 0 && dimscaleid >= 0); - LOG((3, "rec_detach_scales: grp->name %s", grp->name)); + LOG((3, "%s: grp->name %s", __func__, grp->name)); - /* If there are any child groups, attach dimscale there, if needed. */ + /* If there are any child groups, detach dimscale there, if needed. */ for (child_grp = grp->children; child_grp; child_grp = child_grp->next) if ((retval = rec_detach_scales(child_grp, dimid, dimscaleid))) return retval; - /* If there are no vars, we are done. */ - if (!grp->var) - return NC_NOERR; - - /* Find any (already created) vars that use this dimension id. Go - * through the list backwards to accomdate a HDF5 bug. */ - for (var = grp->var; var->next; var = var->next) - ; - - for ( ; var; var = var->prev) + /* Find any vars that use this dimension id. */ + for (var = grp->var; var; var = var->next) for (d = 0; d < var->ndims; d++) if (var->dimids[d] == dimid && !var->dimscale) { - LOG((2, "rec_detach_scales: detaching scale for dimid %d to var %s", - var->dimids[d], var->name)); + LOG((2, "%s: detaching scale for dimid %d to var %s", + __func__, var->dimids[d], var->name)); if (var->created) - { - if (var->dimscale_attached[d]) + if (var->dimscale_attached && var->dimscale_attached[d]) { if (H5DSdetach_scale(var->hdf_datasetid, dimscaleid, d) < 0) return NC_EHDFERR; var->dimscale_attached[d] = 0; } - } } return NC_NOERR; } -static int -getfullname(int grpid, NC_GRP_INFO_T* grp, char** fullnamep) -{ - int retval = NC_NOERR; - size_t len; - char* fullname = NULL; - retval = nc_inq_grpname_full(grpid,&len,NULL); - if(retval != NC_NOERR) goto done; - fullname = (char*)malloc(len+1); - if(fullname == NULL) - {retval = NC_ENOMEM; goto done;} - retval = nc_inq_grpname_full(grpid,&len,fullname); - if(retval != NC_NOERR) goto done; - fullname[len] = '\0'; -done: - if(retval != NC_NOERR) { - if(fullname) free(fullname); - } else { - if(fullnamep) *fullnamep = fullname; - } - return retval; -} - - /* Open the dataset and leave it open. */ int nc4_open_var_grp2(NC_GRP_INFO_T *grp, int varid, hid_t *dataset) @@ -518,7 +484,7 @@ log_dim_info(NC_VAR_INFO_T *var, hsize_t *fdims, hsize_t *fmaxdims, int d2; /* Print some debugging info... */ - LOG((4, "nc4_put_vara: var name %s ndims %d", var->name, var->ndims)); + LOG((4, "%s: var name %s ndims %d", __func__, var->name, var->ndims)); LOG((4, "File space, and requested:")); for (d2 = 0; d2 < var->ndims; d2++) { @@ -548,8 +514,8 @@ set_par_access(NC_HDF5_FILE_INFO_T *h5, NC_VAR_INFO_T *var, hid_t xfer_plistid) if (H5Pset_dxpl_mpio(xfer_plistid, hdf5_xfer_mode) < 0) return NC_EPARINIT; - LOG((4, "hdf5_xfer_mode: %d H5FD_MPIO_COLLECTIVE: %d H5FD_MPIO_INDEPENDENT: %d", - (int)hdf5_xfer_mode, H5FD_MPIO_COLLECTIVE, H5FD_MPIO_INDEPENDENT)); + LOG((4, "%s: %d H5FD_MPIO_COLLECTIVE: %d H5FD_MPIO_INDEPENDENT: %d", + __func__, (int)hdf5_xfer_mode, H5FD_MPIO_COLLECTIVE, H5FD_MPIO_INDEPENDENT)); } return NC_NOERR; } @@ -593,8 +559,8 @@ nc4_put_vara(NC *nc, int ncid, int varid, const size_t *startp, h5 = NC4_DATA(nc); assert(grp && h5 && var && var->name); - LOG((3, "nc4_put_vara: var->name %s mem_nc_type %d is_long %d", - var->name, mem_nc_type, is_long)); + LOG((3, "%s: var->name %s mem_nc_type %d is_long %d", + __func__, var->name, mem_nc_type, is_long)); /* Check some stuff about the type and the file. If the file must * be switched from define mode, it happens here. */ @@ -612,8 +578,8 @@ nc4_put_vara(NC *nc, int ncid, int varid, const size_t *startp, * a non-coordinate (and non-scalar) variable that has the same * name as a dimension. */ if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) && - strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 && - var->ndims) + strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 && + var->ndims) if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, var->hdf5_name, H5P_DEFAULT)) < 0) return NC_ENOTVAR; @@ -915,8 +881,8 @@ nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp, h5 = NC4_DATA(nc); assert(grp && h5 && var && var->name); - LOG((3, "nc4_get_vara: var->name %s mem_nc_type %d is_long %d", - var->name, mem_nc_type, is_long)); + LOG((3, "%s: var->name %s mem_nc_type %d is_long %d", + __func__, var->name, mem_nc_type, is_long)); /* Check some stuff about the type and the file. */ if ((retval = check_for_vara(&mem_nc_type, var, h5))) @@ -933,8 +899,8 @@ nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp, * a non-coordinate (and non-scalar) variable that has the same * name as a dimension. */ if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) && - strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 && - var->ndims) + strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 && + var->ndims) if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, var->hdf5_name, H5P_DEFAULT)) < 0) return NC_ENOTVAR; @@ -1296,6 +1262,7 @@ static int write_netcdf4_dimid(hid_t datasetid, int dimid) { hid_t dimid_spaceid, dimid_attid; + htri_t attr_exists; /* Create the space. */ if ((dimid_spaceid = H5Screate(H5S_SCALAR)) < 0) @@ -1305,19 +1272,21 @@ write_netcdf4_dimid(hid_t datasetid, int dimid) #endif /* Does the attribute already exist? If so, don't try to create it. */ - H5E_BEGIN_TRY { + if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0) + return NC_EHDFERR; + if (attr_exists) dimid_attid = H5Aopen_by_name(datasetid, ".", NC_DIMID_ATT_NAME, H5P_DEFAULT, H5P_DEFAULT); - } H5E_END_TRY; + else + /* Create the attribute if needed. */ + dimid_attid = H5Acreate(datasetid, NC_DIMID_ATT_NAME, + H5T_NATIVE_INT, dimid_spaceid, H5P_DEFAULT); + if (dimid_attid < 0) + return NC_EHDFERR; - /* Create the attribute if needed. */ - if (dimid_attid < 0) - if ((dimid_attid = H5Acreate(datasetid, NC_DIMID_ATT_NAME, - H5T_NATIVE_INT, dimid_spaceid, H5P_DEFAULT)) < 0) - return NC_EHDFERR; /* Write it. */ - LOG((4, "write_netcdf4_dimid: writting secret dimid %d", dimid)); + LOG((4, "%s: writting secret dimid %d", __func__, dimid)); if (H5Awrite(dimid_attid, H5T_NATIVE_INT, &dimid) < 0) return NC_EHDFERR; @@ -1333,7 +1302,7 @@ write_netcdf4_dimid(hid_t datasetid, int dimid) return NC_NOERR; } -/* This function creates the HDF5 dataset for a variabale. */ +/* This function creates the HDF5 dataset for a variable. */ static int var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid) { @@ -1346,7 +1315,7 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid) char *name_to_use; int retval = NC_NOERR; - LOG((3, "var_create_dataset: name %s", var->name)); + LOG((3, "%s:: name %s", __func__, var->name)); /* Scalar or not, we need a creation property list. */ if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0) @@ -1542,7 +1511,7 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid) /* At long last, create the dataset. */ name_to_use = var->hdf5_name ? var->hdf5_name : var->name; - LOG((4, "var_create_dataset: about to H5Dcreate dataset %s of type 0x%x", + LOG((4, "%s: about to H5Dcreate dataset %s of type 0x%x", __func__, name_to_use, typeid)); if ((var->hdf_datasetid = H5Dcreate2(grp->hdf_grpid, name_to_use, typeid, spaceid, H5P_DEFAULT, plistid, access_plistid)) < 0) @@ -1557,16 +1526,6 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid) { if (H5DSset_scale(var->hdf_datasetid, var->name) < 0) BAIL(NC_EHDFERR); - for (dim = grp->dim; dim; dim = dim->next) - if (strcmp(dim->name, var->name) == 0) - { - dim->hdf_dimscaleid = var->hdf_datasetid; - break; - } - - /* Make sure we found a dimension, and gave it a dimscale id. */ - if (!dim || !dim->hdf_dimscaleid) - BAIL(NC_EDIMMETA); /* If this is a multidimensional coordinate variable, write a * coordinates attribute. */ @@ -1576,10 +1535,8 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid) /* If desired, write the netCDF dimid. */ if (write_dimid) - if ((retval = write_netcdf4_dimid(var->hdf_datasetid, - var->dimids[0]))) + if ((retval = write_netcdf4_dimid(var->hdf_datasetid, var->dimids[0]))) BAIL(retval); - } exit: @@ -1654,13 +1611,14 @@ put_att_grpa(NC_GRP_INFO_T *grp, int varid, NC_ATT_INFO_T *att) hid_t datasetid = 0, locid; hid_t attid = 0, spaceid = 0, file_typeid = 0; hsize_t dims[1]; /* netcdf attributes always 1-D. */ + htri_t attr_exists; int retval = NC_NOERR; void *data; int phoney_data = 99; assert(att->name); - LOG((3, "put_att_grpa: varid %d att->attnum %d att->name %s " - "att->xtype %d att->len %d", varid, att->attnum, att->name, + LOG((3, "%s: varid %d att->attnum %d att->name %s att->xtype %d att->len %d", + __func__, varid, att->attnum, att->name, att->xtype, att->len)); /* If the file is read-only, return an error. */ @@ -1678,9 +1636,13 @@ put_att_grpa(NC_GRP_INFO_T *grp, int varid, NC_ATT_INFO_T *att) } /* Delete the att if it exists already. */ - H5E_BEGIN_TRY { - H5Adelete(locid, att->name); - } H5E_END_TRY; + if ((attr_exists = H5Aexists(locid, att->name)) < 0) + return NC_EHDFERR; + if (attr_exists) + { + if (H5Adelete(locid, att->name) < 0) + return NC_EHDFERR; + } /* Get the length ready, and find the HDF type we'll be * writing. */ @@ -2028,9 +1990,18 @@ attach_dimscales(NC_GRP_INFO_T *grp) for (dim1 = g->dim; dim1; dim1 = dim1->next) if (var->dimids[d] == dim1->dimid) { - LOG((2, "attach_dimscales: attaching scale for dimid %d to var %s", - var->dimids[d], var->name)); - if (H5DSattach_scale(var->hdf_datasetid, dim1->hdf_dimscaleid, d) < 0) + hid_t dim_datasetid; /* Dataset ID for dimension */ + + LOG((2, "%s: attaching scale for dimid %d to var %s", + __func__, var->dimids[d], var->name)); + + /* Find dataset ID for dimension */ + if (dim1->coord_var) + dim_datasetid = dim1->coord_var->hdf_datasetid; + else + dim_datasetid = dim1->hdf_dimscaleid; + assert(dim_datasetid > 0); + if (H5DSattach_scale(var->hdf_datasetid, dim_datasetid, d) < 0) BAIL(NC_EHDFERR); var->dimscale_attached[d]++; break; @@ -2052,6 +2023,7 @@ attach_dimscales(NC_GRP_INFO_T *grp) } } /* next d */ } + exit: return retval; } @@ -2067,7 +2039,7 @@ write_attlist(NC_ATT_INFO_T *attlist, int varid, NC_GRP_INFO_T *grp) { if (att->dirty) { - LOG((4, "write_attlist: writing att %s to varid %d", att->name, varid)); + LOG((4, "%s: writing att %s to varid %d", __func__, att->name, varid)); if ((retval = put_att_grpa(grp, varid, att))) return retval; att->dirty = 0; @@ -2077,114 +2049,31 @@ write_attlist(NC_ATT_INFO_T *attlist, int varid, NC_GRP_INFO_T *grp) return NC_NOERR; } -/* Using the HDF5 group iterator is more efficient than the original - * code (O(n) vs O(n**2) for n variables in the group) */ -#define USE_ITERATE_CODE -#ifdef USE_ITERATE_CODE -typedef struct { - char *name; /* The name of the object to searched*/ - int *exists; /* 1 if the object exists, 0 otherswise */ -} var_exists_iter_info; - -/*------------------------------------------------------------------------- - * Function: var_exists_cb - * - * Purpose: Callback routine for checking an object by its name - * - * Return: Exist: 1 - * Not exist: 0 - * Failure: -1 - * - * Programmer: Peter Cao - * 1/25/2012 - * - *------------------------------------------------------------------------- - */ -static int -var_exists_cb(hid_t grpid, const char *name, const H5L_info_t *info, - void *_op_data) -{ - var_exists_iter_info *iter_info = (var_exists_iter_info *)_op_data; - H5I_type_t otype; - hid_t oid; - - if ((oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0) - return H5_ITER_STOP; - - if ((otype = H5Iget_type( oid ))<0) { - H5Oclose(oid); - return H5_ITER_STOP; - } - H5Oclose(oid); - - if (otype == H5I_DATASET) { - if (!strcmp(iter_info->name, name)) { - *(iter_info->exists) = 1; - return (H5_ITER_STOP); - } - } - - return (H5_ITER_CONT); -} /* end var_exists_cb() */ - static int var_exists(hid_t grpid, char *name, int *exists) { - hsize_t num_obj; - var_exists_iter_info iter_info; - iter_info.name = name; - iter_info.exists = exists; + htri_t link_exists; - if (H5Gget_num_objs(grpid, &num_obj) < 0) - return NC_EVARMETA; - - if (!name) - return NC_NOERR; - - *exists = 0; - if (H5Literate(grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, var_exists_cb, &iter_info) < 0) - return NC_EHDFERR; - - return NC_NOERR; -} -#else -static int -var_exists(hid_t grpid, char *name, int *exists) -{ - hsize_t num_obj, i; - H5O_info_t obj_info; - int obj_class; - char obj_name[NC_MAX_NAME + 1]; - ssize_t size; - int retval = NC_NOERR; - + /* Reset the boolean */ *exists = 0; - if (H5Gget_num_objs(grpid, &num_obj) < 0) - return NC_EVARMETA; - for (i = 0; i < num_obj; i++) + + /* Check if the object name exists in the group */ + if ((link_exists = H5Lexists(grpid, name, H5P_DEFAULT)) < 0) + return NC_EHDFERR; + if (link_exists) { - if (H5Oget_info_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i, &obj_info, H5P_DEFAULT) < 0) + H5G_stat_t statbuf; + + /* Get info about the object */ + if (H5Gget_objinfo(grpid, name, 1, &statbuf) < 0) return NC_EHDFERR; - obj_class = obj_info.type; - if ((size = H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i, NULL, 0, H5P_DEFAULT)) < 0) - return NC_EHDFERR; - if (size > NC_MAX_NAME) - return NC_EMAXNAME; - if (H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i, obj_name, size+1, H5P_DEFAULT) < 0) - return NC_EHDFERR; - if (obj_class == H5O_TYPE_DATASET) - { - if (!strncmp(name, obj_name, NC_MAX_NAME)) - { - *exists = 1; - return NC_NOERR; - } - } + + if (H5G_DATASET == statbuf.type) + *exists = 1; } - return retval; + return NC_NOERR; } -#endif /* USE_ITERATE_CODE */ /* This function writes a variable. The principle difficulty comes * from the possibility that this is a coordinate variable, and was @@ -2201,13 +2090,12 @@ write_var(NC_VAR_INFO_T *var, NC_GRP_INFO_T *grp, int write_dimid) if (!var->dirty) { if (write_dimid && var->ndims) - if ((retval = write_netcdf4_dimid(var->hdf_datasetid, - var->dimids[0]))) + if ((retval = write_netcdf4_dimid(var->hdf_datasetid, var->dimids[0]))) BAIL(retval); } else { - LOG((4, "write_var: writing var %s", var->name)); + LOG((4, "%s: writing var %s", __func__, var->name)); if (var->created) replace_existing_var = 1; @@ -2226,26 +2114,30 @@ write_var(NC_VAR_INFO_T *var, NC_GRP_INFO_T *grp, int write_dimid) * this object exists in the HDF group. */ if (var->dimscale) for (d1 = grp->dim; d1; d1 = d1->next) - if (!strcmp(d1->name, var->name) || - !strcmp(d1->old_name, var->name)) + if (!strcmp(d1->name, var->name)) { if ((retval = var_exists(grp->hdf_grpid, var->name, &exists))) return retval; if (exists) { + hid_t dim_datasetid; /* Dataset ID for dimension */ + + /* Indicate that the variable already exists */ replace_existing_var++; + /* Find dataset ID for dimension */ + if (d1->coord_var) + dim_datasetid = d1->coord_var->hdf_datasetid; + else + dim_datasetid = d1->hdf_dimscaleid; + assert(dim_datasetid > 0); + /* If we're replacing an existing dimscale dataset, go to - * every var in the file and detatch this dimension scale, + * every var in the file and detach this dimension scale, * because we have to delete it. */ if ((retval = rec_detach_scales(grp->nc4_info->root_grp, - var->dimids[0], d1->hdf_dimscaleid))) + var->dimids[0], dim_datasetid))) return retval; - - /* Check if this variable should no longer be a dimscale */ - /* (Because its dim was renamed) */ - if (!strcmp(d1->old_name, var->name)) - var->dimscale = 0; break; } } @@ -2253,15 +2145,8 @@ write_var(NC_VAR_INFO_T *var, NC_GRP_INFO_T *grp, int write_dimid) /* Delete the HDF5 dataset that is to be replaced. */ if (replace_existing_var) { - /* If this is a dimension scale, do this stuff. */ - if (d1) - { - assert(d1 && d1->hdf_dimscaleid); - if (H5Dclose(d1->hdf_dimscaleid) < 0) - return NC_EDIMMETA; - d1->hdf_dimscaleid = 0; - } - else + /* If this is not a dimension scale, do this stuff. */ + if (!var->dimscale && var->dimscale_attached) { int dims_detached = 0; int finished = 0; @@ -2271,24 +2156,32 @@ write_var(NC_VAR_INFO_T *var, NC_GRP_INFO_T *grp, int write_dimid) /* If this is a regular var, detach all its dim scales. */ for (d = 0; d < var->ndims; d++) - for (g = grp; g && !finished; g = g->parent) - for (dim1 = g->dim; dim1; dim1 = dim1->next) - if (var->dimids[d] == dim1->dimid) - { - if(var->hdf_datasetid != dim1->hdf_dimscaleid) - if (H5DSdetach_scale(var->hdf_datasetid, dim1->hdf_dimscaleid, d) < 0) - BAIL(NC_EHDFERR); - if(var->dimscale_attached) - var->dimscale_attached[d] = 0; - if (dims_detached++ == var->ndims) - finished++; - } - - /* Free the HDF5 dataset id. */ - if (var->hdf_datasetid && H5Dclose(var->hdf_datasetid) < 0) - BAIL(NC_EHDFERR); - var->hdf_datasetid = 0; + if (var->dimscale_attached[d]) + for (g = grp; g && !finished; g = g->parent) + for (dim1 = g->dim; dim1; dim1 = dim1->next) + if (var->dimids[d] == dim1->dimid) + { + hid_t dim_datasetid; /* Dataset ID for dimension */ + + /* Find dataset ID for dimension */ + if (dim1->coord_var) + dim_datasetid = dim1->coord_var->hdf_datasetid; + else + dim_datasetid = dim1->hdf_dimscaleid; + assert(dim_datasetid > 0); + + if (H5DSdetach_scale(var->hdf_datasetid, dim_datasetid, d) < 0) + BAIL(NC_EHDFERR); + var->dimscale_attached[d] = 0; + if (dims_detached++ == var->ndims) + finished++; + } } + + /* Free the HDF5 dataset id. */ + if (var->hdf_datasetid && H5Dclose(var->hdf_datasetid) < 0) + BAIL(NC_EHDFERR); + var->hdf_datasetid = 0; /* Now delete the variable. */ if (H5Gunlink(grp->hdf_grpid, var->name) < 0) @@ -2299,14 +2192,12 @@ write_var(NC_VAR_INFO_T *var, NC_GRP_INFO_T *grp, int write_dimid) if ((retval = var_create_dataset(grp, var, write_dimid))) return retval; - /* Reattach this scale everywhere it is used. (Recall that - * netCDF dimscales are always 1-D). */ - /* (Only do this if the variable is still a dimscale) */ - if (d1 && replace_existing_var && var->dimscale) + /* If this is a dimension scale, reattach the scale everywhere it + * is used. (Recall that netCDF dimscales are always 1-D). */ + if (replace_existing_var && var->dimscale) { - d1->hdf_dimscaleid = var->hdf_datasetid; if ((retval = rec_reattach_scales(grp->nc4_info->root_grp, - var->dimids[0], d1->hdf_dimscaleid))) + var->dimids[0], var->hdf_datasetid))) return retval; } } @@ -2324,83 +2215,75 @@ write_var(NC_VAR_INFO_T *var, NC_GRP_INFO_T *grp, int write_dimid) static int write_dim(NC_DIM_INFO_T *dim, NC_GRP_INFO_T *grp, int write_dimid) { - hid_t spaceid, create_propid; - hsize_t dims[1], max_dims[1], chunk_dims[1] = {1}; - int dimscale_exists = 0; - char dimscale_wo_var[NC_MAX_NAME]; int retval; - if (dim->dirty) + /* If there's no dimscale dataset for this dim, create one, + * and mark that it should be hidden from netCDF as a + * variable. (That is, it should appear as a dimension + * without an associated variable.) */ + if (0 == dim->hdf_dimscaleid) { - /* If there's no dimscale dataset for this dim, create one, - * and mark that it should be hidden from netCDF as a - * variable. (That is, it should appear as a dimension - * without an associated variable.) */ - if (!dimscale_exists) + hid_t spaceid, create_propid; + hsize_t dims[1], max_dims[1], chunk_dims[1] = {1}; + char dimscale_wo_var[NC_MAX_NAME]; + + LOG((4, "%s: creating dim %s", __func__, dim->name)); + + /* Sanity check */ + assert(NULL == dim->coord_var); + + /* Create a property list. If this dimension scale is + * unlimited (i.e. it's an unlimited dimension), then set + * up chunking, with a chunksize of 1. */ + if ((create_propid = H5Pcreate(H5P_DATASET_CREATE)) < 0) + BAIL(NC_EHDFERR); +#ifdef EXTRA_TESTS + num_plists++; +#endif + dims[0] = dim->len; + max_dims[0] = dim->len; + if (dim->unlimited) { - LOG((4, "write_dim: creating dim %s", dim->name)); - - /* Create a property list. If this dimension scale is - * unlimited (i.e. it's an unlimited dimension), then set - * up chunking, with a chunksize of 1. */ - if ((create_propid = H5Pcreate(H5P_DATASET_CREATE)) < 0) + max_dims[0] = H5S_UNLIMITED; + if (H5Pset_chunk(create_propid, 1, chunk_dims) < 0) BAIL(NC_EHDFERR); -#ifdef EXTRA_TESTS - num_plists++; -#endif - dims[0] = dim->len; - max_dims[0] = dim->len; - if (dim->unlimited) - { - max_dims[0] = H5S_UNLIMITED; - if (H5Pset_chunk(create_propid, 1, chunk_dims) < 0) - BAIL(NC_EHDFERR); - } - - /* Set up space. */ - if ((spaceid = H5Screate_simple(1, dims, max_dims)) < 0) - BAIL(NC_EHDFERR); -#ifdef EXTRA_TESTS - num_spaces++; -#endif - - /* If we define, and then rename this dimension before - * creation of the dimscale dataset, then we can throw - * away the old_name of the dimension. */ - if (dim->old_name && strlen(dim->old_name)) - strcpy(dim->old_name, ""); - - if (H5Pset_attr_creation_order(create_propid, H5P_CRT_ORDER_TRACKED| - H5P_CRT_ORDER_INDEXED) < 0) - BAIL(NC_EHDFERR); - - /* Create the dataset that will be the dimension scale. */ - LOG((4, "write_dim: about to H5Dcreate a dimscale dataset %s", dim->name)); - if ((dim->hdf_dimscaleid = H5Dcreate1(grp->hdf_grpid, dim->name, H5T_IEEE_F32BE, - spaceid, create_propid)) < 0) - BAIL(NC_EHDFERR); - - /* Close the spaceid and create_propid. */ - if (H5Sclose(spaceid) < 0) - BAIL(NC_EHDFERR); -#ifdef EXTRA_TESTS - num_spaces--; -#endif - if (H5Pclose(create_propid) < 0) - BAIL(NC_EHDFERR); -#ifdef EXTRA_TESTS - num_plists--; -#endif - - /* Indicate that this is a scale. Also indicate that not - * be shown to the user as a variable. It is hidden. It is - * a DIM WITHOUT A VARIABLE! */ - sprintf(dimscale_wo_var, "%s%10d", DIM_WITHOUT_VARIABLE, (int)dim->len); - if (H5DSset_scale(dim->hdf_dimscaleid, dimscale_wo_var) < 0) - BAIL(NC_EHDFERR); - } - dim->dirty = 0; + + /* Set up space. */ + if ((spaceid = H5Screate_simple(1, dims, max_dims)) < 0) + BAIL(NC_EHDFERR); +#ifdef EXTRA_TESTS + num_spaces++; +#endif + + if (H5Pset_attr_creation_order(create_propid, H5P_CRT_ORDER_TRACKED| + H5P_CRT_ORDER_INDEXED) < 0) + BAIL(NC_EHDFERR); + + /* Create the dataset that will be the dimension scale. */ + LOG((4, "%s: about to H5Dcreate a dimscale dataset %s", __func__, dim->name)); + if ((dim->hdf_dimscaleid = H5Dcreate1(grp->hdf_grpid, dim->name, H5T_IEEE_F32BE, + spaceid, create_propid)) < 0) + BAIL(NC_EHDFERR); + + /* Close the spaceid and create_propid. */ + if (H5Sclose(spaceid) < 0) + BAIL(NC_EHDFERR); +#ifdef EXTRA_TESTS + num_spaces--; +#endif + if (H5Pclose(create_propid) < 0) + BAIL(NC_EHDFERR); +#ifdef EXTRA_TESTS + num_plists--; +#endif + + /* Indicate that this is a scale. Also indicate that not + * be shown to the user as a variable. It is hidden. It is + * a DIM WITHOUT A VARIABLE! */ + sprintf(dimscale_wo_var, "%s%10d", DIM_WITHOUT_VARIABLE, (int)dim->len); + if (H5DSset_scale(dim->hdf_dimscaleid, dimscale_wo_var) < 0) + BAIL(NC_EHDFERR); } /* Did we extend an unlimited dimension? */ @@ -2450,24 +2333,12 @@ write_dim(NC_DIM_INFO_T *dim, NC_GRP_INFO_T *grp, int write_dimid) } } - /* Did we rename this dimension? */ - if (dim->old_name && strlen(dim->old_name)) - { - /* Rename the dimension's dataset in the HDF5 file. */ - if (H5Gmove2(grp->hdf_grpid, dim->old_name, grp->hdf_grpid, dim->name) < 0) - return NC_EHDFERR; - - /* Reset old_name. */ - strcpy(dim->old_name, ""); - } - /* If desired, write the secret dimid. This will be used instead of * the dimid that the dimension would otherwise receive based on * creation order. This can be necessary when dims and their * coordinate variables were created in different order. */ if (write_dimid && dim->hdf_dimscaleid) - if ((retval = write_netcdf4_dimid(dim->hdf_dimscaleid, - dim->dimid))) + if ((retval = write_netcdf4_dimid(dim->hdf_dimscaleid, dim->dimid))) BAIL(retval); return NC_NOERR; @@ -2484,56 +2355,51 @@ write_dim(NC_DIM_INFO_T *dim, NC_GRP_INFO_T *grp, int write_dimid) int nc4_rec_detect_need_to_preserve_dimids(NC_GRP_INFO_T *grp, int *bad_coord_orderp) { - NC_DIM_INFO_T *dim; NC_VAR_INFO_T *var; NC_GRP_INFO_T *child_grp; int last_dimid = -1; int retval; - /* If the user writes coord vars in a different order then he - * defined their dimensions, then, when the file is reopened, the - * order of the dimids will change to match the order of the coord - * vars. Detect if this is about to happen. */ + /* Iterate over variables in this group */ for (var = grp->var; var; var = var->next) { - LOG((5, "checking %s for out of order coord var", var->name)); - if (var->ndims && var->dimscale) + /* Only matters for dimension scale variables, with non-scalar dimensionality */ + if (var->dimscale && var->ndims) { + /* If the user writes coord vars in a different order then he + * defined their dimensions, then, when the file is reopened, the + * order of the dimids will change to match the order of the coord + * vars. Detect if this is about to happen. */ if (var->dimids[0] < last_dimid) - { - *bad_coord_orderp = 1; - return NC_NOERR; - } - last_dimid = var->dimids[0]; + { + LOG((5, "%s: %s is out of order coord var", __func__, var->name)); + *bad_coord_orderp = 1; + return NC_NOERR; + } + last_dimid = var->dimids[0]; + + /* If there are multidimensional coordinate variables defined, then + * it's also necessary to preserve dimension IDs when the file is + * reopened ... */ + if (var->ndims > 1) + { + LOG((5, "%s: %s is multidimensional coord var", __func__, var->name)); + *bad_coord_orderp = 1; + return NC_NOERR; + } + + /* Did the user define a dimension, end define mode, reenter define + * mode, and then define a coordinate variable for that dimension? + * If so, dimensions will be out of order. */ + if (var->dirty && !var->created) + { + LOG((5, "%s: coord var defined after enddef/redef", __func__)); + *bad_coord_orderp = 1; + return NC_NOERR; + } } } - /* If there are multidimensional coordinate variables defined, then - * it's also necessary to preserve dimension IDs when the file is - * reopened ... */ - for (var = grp->var; var; var = var->next) - { - LOG((5, "checking %s for multidimensional coord var", var->name)); - if (var->ndims > 1 && var->dimscale) - { - *bad_coord_orderp = 1; - return NC_NOERR; - } - } - - /* Did the user define a dimension, end define mode, reenter define - * mode, and then define a coordinate variable for that dimension? - * If so, dimensions will be out of order. */ - for (var = grp->var; var; var = var->next) - if (var->dirty && !var->created && var->ndims) - for (dim = grp->dim; dim; dim = dim->next) - if (!strcmp(dim->name, var->name) && !dim->dirty) - { - LOG((5, "coord var defined after enddef/redef")); - *bad_coord_orderp = 1; - return NC_NOERR; - } - /* If there are any child groups, check them also for this condition. */ for (child_grp = grp->children; child_grp; child_grp = child_grp->next) if ((retval = nc4_rec_detect_need_to_preserve_dimids(child_grp, bad_coord_orderp))) @@ -2557,7 +2423,7 @@ nc4_rec_write_metadata(NC_GRP_INFO_T *grp, int bad_coord_order) int retval; assert(grp && grp->name && grp->hdf_grpid); - LOG((3, "nc4_rec_write_metadata: grp->name %s, bad_coord_order %d", grp->name, bad_coord_order)); + LOG((3, "%s: grp->name %s, bad_coord_order %d", __func__, grp->name, bad_coord_order)); /* Write global attributes for this group. */ if ((retval = write_attlist(grp->att, NC_GLOBAL, grp))) @@ -2581,15 +2447,15 @@ nc4_rec_write_metadata(NC_GRP_INFO_T *grp, int bad_coord_order) * has an associated coord var. */ for (found_coord = 0; dim && !found_coord; dim = dim->prev) { - if (!dim->coord_var_in_grp) + if (!dim->coord_var) { if ((retval = write_dim(dim, grp, bad_coord_order))) return retval; } else { - found_coord++; coord_varid = dim->coord_var->varid; + found_coord++; } } @@ -2607,37 +2473,6 @@ nc4_rec_write_metadata(NC_GRP_INFO_T *grp, int bad_coord_order) if ((retval = attach_dimscales(grp))) return retval; - /* Rename this group */ - if (grp->old_name && strlen(grp->old_name)) - { - /* We need to get the full name for the new name and the old name */ - char* oldfullname = NULL; - char* newfullname = NULL; - char* tmp = NULL; - int nc_groupid = 0; - /* Construct the group's full ncid */ - nc_groupid = (grp->nc4_info->controller->ext_ncid) | (grp->nc_grpid); - /* Temporarily make group's name be old name so we can get the - old full name */ - tmp = grp->name; - grp->name = grp->old_name; - retval = getfullname(nc_groupid,grp,&oldfullname); - if(retval != NC_NOERR) goto done; - /* repeat for the new name */ - grp->name = tmp; - retval = getfullname(nc_groupid,grp,&newfullname); - if(retval != NC_NOERR) goto done; - - if(H5Lmove(grp->nc4_info->hdfid, oldfullname, grp->nc4_info->hdfid, newfullname, H5P_DEFAULT, H5P_DEFAULT) < 0) - {retval = NC_EHDFERR; goto done;} - /* Reset old_name. */ - strcpy(grp->old_name, ""); -done: - if(oldfullname) free(oldfullname); - if(newfullname) free(newfullname); - if(retval) return retval; - } - /* If there are any child groups, write their metadata. */ for (child_grp = grp->children; child_grp; child_grp = child_grp->next) if ((retval = nc4_rec_write_metadata(child_grp, bad_coord_order))) @@ -2648,14 +2483,14 @@ done: /* Recursively write all groups and types. */ int -nc4_rec_write_types(NC_GRP_INFO_T *grp) +nc4_rec_write_groups_types(NC_GRP_INFO_T *grp) { NC_GRP_INFO_T *child_grp; NC_TYPE_INFO_T *type; int retval; assert(grp && grp->name); - LOG((3, "nc4_rec_write_types: grp->name %s", grp->name)); + LOG((3, "%s: grp->name %s", __func__, grp->name)); /* Create the group in the HDF5 file if it doesn't exist. */ if (!grp->hdf_grpid) @@ -2675,7 +2510,7 @@ nc4_rec_write_types(NC_GRP_INFO_T *grp) /* If there are any child groups, write their groups and types. */ for (child_grp = grp->children; child_grp; child_grp = child_grp->next) - if ((retval = nc4_rec_write_types(child_grp))) + if ((retval = nc4_rec_write_groups_types(child_grp))) return retval; return NC_NOERR; @@ -2747,8 +2582,7 @@ nc4_pg_varm(NC_PG_T pg, NC *nc, int ncid, int varid, const size_t *start, int i; int retval = NC_NOERR; - LOG((3, "nc4_pg_varm: ncid 0x%x varid %d xtype %d", ncid, varid, - xtype)); + LOG((3, "%s: ncid 0x%x varid %d xtype %d", __func__, ncid, varid, xtype)); /* Find metadata for this file and var. */ assert(nc); @@ -3048,8 +2882,8 @@ nc4_convert_type(const void *src, void *dest, size_t count = 0; *range_error = 0; - LOG((3, "nc4_convert_type: len %d src_type %d dest_type %d src_long %d" - " dest_long %d", len, src_type, dest_type, src_long, dest_long)); + LOG((3, "%s: len %d src_type %d dest_type %d src_long %d dest_long %d", + __func__, len, src_type, dest_type, src_long, dest_long)); /* OK, this is ugly. If you can think of anything better, I'm open to suggestions! @@ -3069,7 +2903,7 @@ nc4_convert_type(const void *src, void *dest, *cp1++ = *cp++; break; default: - LOG((0, "nc4_convert_type: Uknown destination type.")); + LOG((0, "%s: Uknown destination type.", __func__)); } break; case NC_BYTE: @@ -3141,8 +2975,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *bp++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } break; @@ -3203,8 +3037,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *ubp++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } break; @@ -3276,8 +3110,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *sp++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } break; @@ -3341,8 +3175,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *usp++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } break; @@ -3432,8 +3266,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *lp++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } } @@ -3522,8 +3356,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *ip++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } } @@ -3604,8 +3438,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *uip++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } break; @@ -3689,8 +3523,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *lip++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } break; @@ -3774,8 +3608,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *ulip++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } break; @@ -3867,8 +3701,8 @@ nc4_convert_type(const void *src, void *dest, *dp++ = *fp++; break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } break; @@ -3964,14 +3798,14 @@ nc4_convert_type(const void *src, void *dest, } break; default: - LOG((0, "nc4_convert_type: unexpected dest type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } break; default: - LOG((0, "nc4_convert_type: unexpected src type. " - "src_type %d, dest_type %d", src_type, dest_type)); + LOG((0, "%s: unexpected src type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); return NC_EBADTYPE; } return NC_NOERR; @@ -3986,12 +3820,10 @@ nc4_rec_match_dimscales(NC_GRP_INFO_T *grp) NC_GRP_INFO_T *g; NC_VAR_INFO_T *var; NC_DIM_INFO_T *dim; - H5G_stat_t statbuf; - int d, finished; int retval = NC_NOERR; assert(grp && grp->name); - LOG((4, "nc4_rec_match_dimscales: grp->name %s", grp->name)); + LOG((4, "%s: grp->name %s", __func__, grp->name)); /* Perform var dimscale match for child groups. */ for (g = grp->children; g; g = g->next) @@ -4002,49 +3834,48 @@ nc4_rec_match_dimscales(NC_GRP_INFO_T *grp) * try and find a dimension for them. */ for (var = grp->var; var; var = var->next) { - /* Are there dimscales for this variable? */ - if (var->dimscale_hdf5_objids) + /* Skip dimension scale variables */ + if (!var->dimscale) { - for (d = 0; d < var->ndims; d++) + int d; + + /* Are there dimscales for this variable? */ + if (var->dimscale_hdf5_objids) { - LOG((5, "nc4_rec_match_dimscales: var %s has dimscale info...", var->name)); - /* Look at all the dims in this group to see if they - * match. */ - finished = 0; - for (g = grp; g && !finished; g = g->parent) + for (d = 0; d < var->ndims; d++) { - for (dim = g->dim; dim; dim = dim->next) + int finished = 0; + + LOG((5, "%s: var %s has dimscale info...", __func__, var->name)); + /* Look at all the dims in this group to see if they + * match. */ + for (g = grp; g && !finished; g = g->parent) { - if (!dim->hdf_dimscaleid) - return NC_EDIMMETA; - if (H5Gget_objinfo(dim->hdf_dimscaleid, ".", 1, &statbuf) < 0) - return NC_EHDFERR; - if (var->dimscale_hdf5_objids[d].fileno[0] == statbuf.fileno[0] && - var->dimscale_hdf5_objids[d].objno[0] == statbuf.objno[0] && - var->dimscale_hdf5_objids[d].fileno[1] == statbuf.fileno[1] && - var->dimscale_hdf5_objids[d].objno[1] == statbuf.objno[1]) + for (dim = g->dim; dim; dim = dim->next) { - LOG((4, "nc4_rec_match_dimscales: for dimension %d, found dim %s", - d, dim->name)); - var->dimids[d] = dim->dimid; - finished++; - break; - } - } /* next dim */ - } /* next grp */ - LOG((5, "nc4_rec_match_dimscales: dimid for this dimscale is %d", var->xtype)); - } /* next var->dim */ - } - else - { - if (!var->dimscale) - { + if (var->dimscale_hdf5_objids[d].fileno[0] == dim->hdf5_objid.fileno[0] && + var->dimscale_hdf5_objids[d].objno[0] == dim->hdf5_objid.objno[0] && + var->dimscale_hdf5_objids[d].fileno[1] == dim->hdf5_objid.fileno[1] && + var->dimscale_hdf5_objids[d].objno[1] == dim->hdf5_objid.objno[1]) + { + LOG((4, "%s: for dimension %d, found dim %s", + __func__, d, dim->name)); + var->dimids[d] = dim->dimid; + finished++; + break; + } + } /* next dim */ + } /* next grp */ + LOG((5, "%s: dimid for this dimscale is %d", __func__, var->xtype)); + } /* next var->dim */ + } + /* No dimscales for this var! Invent phony dimensions. */ + else + { hid_t spaceid = 0; hsize_t *h5dimlen = NULL, *h5dimlenmax = NULL; int dataset_ndims; - /* No dimscales for this var! Invent phony dimensions. */ - /* Find the space information for this dimension. */ if ((spaceid = H5Dget_space(var->hdf_datasetid)) < 0) return NC_EHDFERR; @@ -4087,9 +3918,6 @@ nc4_rec_match_dimscales(NC_GRP_INFO_T *grp) * size. */ for (d = 0; d < var->ndims; d++) { - NC_DIM_INFO_T *dim = NULL; - char phony_dim_name[NC_MAX_NAME + 1]; - /* Is there already a phony dimension of the correct size? */ for (dim = grp->dim; dim; dim = dim->next) if ((dim->len == h5dimlen[d]) && @@ -4100,7 +3928,9 @@ nc4_rec_match_dimscales(NC_GRP_INFO_T *grp) /* Didn't find a phony dim? Then create one. */ if (!dim) { - LOG((3, "nc4_rec_match_dimscales: creating phony dim for var %s", var->name)); + char phony_dim_name[NC_MAX_NAME + 1]; + + LOG((3, "%s: creating phony dim for var %s", __func__, var->name)); if ((retval = nc4_dim_list_add(&grp->dim))) return retval; grp->ndims++; @@ -4137,7 +3967,7 @@ nc4_get_typelen_mem(NC_HDF5_FILE_INFO_T *h5, nc_type xtype, int is_long, NC_TYPE_INFO_T *type; int retval; - LOG((4, "nc4_get_typelen_mem xtype: %d", xtype)); + LOG((4, "%s xtype: %d", __func__, xtype)); assert(len); /* If this is an atomic type, the answer is easy. */ diff --git a/libsrc4/nc4internal.c b/libsrc4/nc4internal.c index f6befe2c3..ad0e597a2 100644 --- a/libsrc4/nc4internal.c +++ b/libsrc4/nc4internal.c @@ -16,6 +16,7 @@ conditions. #include "nc4internal.h" #include "nc.h" /* from libsrc */ #include "ncdispatch.h" /* from libdispatch */ +#include "H5DSpublic.h" #include #if 0 /*def USE_PNETCDF*/ @@ -125,7 +126,7 @@ find_var_dim_max_length(NC_GRP_INFO_T *grp, int varid, int dimid, size_t *maxlen if ((dataset_ndims = H5Sget_simple_extent_dims(spaceid, h5dimlen, h5dimlenmax)) < 0) BAIL(NC_EHDFERR); - LOG((5, "find_var_shape_nc: varid %d len %d max: %d", + LOG((5, "find_var_dim_max_length: varid %d len %d max: %d", varid, (int)h5dimlen[0], (int)h5dimlenmax[0])); for (d=0; ddimids[d] == dimid) { @@ -176,30 +177,10 @@ nc4_nc4f_list_add(NC *nc, const char *path, int mode) return nc4_grp_list_add(&(h5->root_grp), h5->next_nc_grpid++, NULL, nc, NC_GROUP_NAME, &grp); } -/* /\* Given an ncid, find the relevant group and return a pointer to */ -/* * it. *\/ */ -/* NC_GRP_INFO_T * */ -/* find_nc_grp(int ncid) */ -/* { */ -/* NC *f; */ - -/* for (f = nc_file; f; f = f->next) */ -/* { */ -/* if (f->ext_ncid == (ncid & FILE_ID_MASK)) */ -/* { */ -/* assert(f->nc4_info && f->nc4_info->root_grp); */ -/* return nc4_rec_find_grp(f->nc4_info->root_grp, (ncid & GRP_ID_MASK)); */ -/* } */ -/* } */ - -/* return NULL; */ -/* } */ /* Given an ncid, find the relevant group and return a pointer to it, * return an error of this is not a netcdf-4 file (or if strict nc3 is * turned on for this file.) */ - - int nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp) { @@ -365,6 +346,20 @@ nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim, return NC_NOERR; } +/* Find a var (by name) in a grp. */ +int +nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var) +{ + assert(grp && var && name); + + /* Find the var info. */ + for ((*var) = grp->var; (*var); (*var) = (*var)->next) + if (0 == strcmp(name, (*var)->name)) + break; + + return NC_NOERR; +} + /* Recursively hunt for a HDF type id. */ NC_TYPE_INFO_T * nc4_rec_find_hdf_type(NC_GRP_INFO_T *start_grp, hid_t target_hdf_typeid) @@ -703,8 +698,7 @@ nc4_grp_list_add(NC_GRP_INFO_T **list, int new_nc_grpid, { NC_GRP_INFO_T *g; - LOG((3, "grp_list_add: new_nc_grpid %d name %s ", - new_nc_grpid, name)); + LOG((3, "%s: new_nc_grpid %d name %s ", __func__, new_nc_grpid, name)); /* Get the memory to store this groups info. */ if (!(*grp = calloc(1, sizeof(NC_GRP_INFO_T)))) @@ -1089,8 +1083,6 @@ nc4_dim_list_del(NC_DIM_INFO_T **list, NC_DIM_INFO_T *dim) /* Free memory allocated for names. */ if (dim->name) free(dim->name); - if (dim->old_name) - free(dim->old_name); free(dim); return NC_NOERR; @@ -1125,7 +1117,7 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) int retval; assert(grp); - LOG((3, "nc4_rec_grp_del: grp->name %s", grp->name)); + LOG((3, "%s: grp->name %s", __func__, grp->name)); /* Recursively call this function for each child, if any, stopping * if there is an error. */ @@ -1143,7 +1135,7 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) att = grp->att; while (att) { - LOG((4, "nc4_rec_grp_del: deleting att %s", att->name)); + LOG((4, "%s: deleting att %s", __func__, att->name)); a = att->next; if ((retval = nc4_att_list_del(&grp->att, att))) return retval; @@ -1154,11 +1146,10 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) var = grp->var; while (var) { - LOG((4, "nc4_rec_grp_del: deleting var %s", var->name)); + LOG((4, "%s: deleting var %s", __func__, var->name)); /* Close HDF5 dataset associated with this var, unless it's a * scale. */ - if (var->hdf_datasetid && !var->dimscale && - H5Dclose(var->hdf_datasetid) < 0) + if (var->hdf_datasetid && H5Dclose(var->hdf_datasetid) < 0) return NC_EHDFERR; v = var->next; if ((retval = nc4_var_list_del(&grp->var, var))) @@ -1170,7 +1161,7 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) dim = grp->dim; while (dim) { - LOG((4, "nc4_rec_grp_del: deleting dim %s", dim->name)); + LOG((4, "%s: deleting dim %s", __func__, dim->name)); /* Close HDF5 dataset associated with this dim. */ if (dim->hdf_dimscaleid && H5Dclose(dim->hdf_dimscaleid) < 0) return NC_EHDFERR; @@ -1184,7 +1175,7 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) type = grp->type; while (type) { - LOG((4, "nc4_rec_grp_del: deleting type %s", type->name)); + LOG((4, "%s: deleting type %s", __func__, type->name)); t = type->next; if ((retval = type_list_del(&grp->type, type))) return retval; @@ -1192,7 +1183,7 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) } /* Tell HDF5 we're closing this group. */ - LOG((4, "nc4_rec_grp_del: closing group %s", grp->name)); + LOG((4, "%s: closing group %s", __func__, grp->name)); if (grp->hdf_grpid && H5Gclose(grp->hdf_grpid) < 0) return NC_EHDFERR; @@ -1262,6 +1253,113 @@ nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att) return NC_NOERR; } +/* Break a coordinate variable to separate the dimension and the variable */ +int +nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T *dim) +{ + int retval = NC_NOERR; + + /* Sanity checks */ + assert(dim->coord_var == coord_var); + assert(coord_var->dim[0] == dim); + assert(coord_var->dimids[0] == dim->dimid); + assert(0 == dim->hdf_dimscaleid); + + /* If we're replacing an existing dimscale dataset, go to + * every var in the file and detach this dimension scale. */ + if ((retval = rec_detach_scales(grp->nc4_info->root_grp, + dim->dimid, coord_var->hdf_datasetid))) + return retval; + + /* Allow attached dimscales to be tracked on the [former] coordinate variable */ + if (coord_var->ndims) + { + /* Coordinate variables shouldn't have dimscales attached */ + assert(NULL == coord_var->dimscale_attached); + + /* Allocate space for tracking them */ + if (NULL == (coord_var->dimscale_attached = calloc(coord_var->ndims, sizeof(int)))) + return NC_ENOMEM; + } + + /* Detach dimension from variable */ + coord_var->dimscale = 0; + coord_var->dirty++; + dim->coord_var = NULL; + + return NC_NOERR; +} + +/* Reform a coordinate variable from a dimension and a variable */ +int +nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim) +{ + int retval = NC_NOERR; + + /* Attach variable to dimension */ + var->dimscale++; + var->dirty++; + dim->coord_var = var; + + /* Detach dimscales from the [new] coordinate variable */ + if(var->dimscale_attached) + { + int dims_detached = 0; + int finished = 0; + int d; + + /* Loop over all dimensions for variable */ + for (d = 0; d < var->ndims && !finished; d++) + /* Is there a dimscale attached to this axis? */ + if(var->dimscale_attached[d]) + { + NC_GRP_INFO_T *g; + + for (g = grp; g && !finished; g = g->parent) + { + NC_DIM_INFO_T *dim1; + + for (dim1 = g->dim; dim1 && !finished; dim1 = dim1->next) + if (var->dimids[d] == dim1->dimid) + { + hid_t dim_datasetid; /* Dataset ID for dimension */ + + /* Find dataset ID for dimension */ + if (dim1->coord_var) + dim_datasetid = dim1->coord_var->hdf_datasetid; + else + dim_datasetid = dim1->hdf_dimscaleid; + assert(dim_datasetid > 0); + if (H5DSdetach_scale(var->hdf_datasetid, dim_datasetid, d) < 0) + BAIL(NC_EHDFERR); + var->dimscale_attached[d] = 0; + if (dims_detached++ == var->ndims) + finished++; + } + } + } + + /* Release & reset the array tracking attached dimscales */ + free(var->dimscale_attached); + var->dimscale_attached = NULL; + } + + /* Use variable's dataset ID for the dimscale ID */ + if (dim->hdf_dimscaleid) + { + if (H5Dclose(dim->hdf_dimscaleid) < 0) + BAIL(NC_EHDFERR); + dim->hdf_dimscaleid = 0; + + /* Now delete the dimscale's dataset (it will be recreated later, if necessary) */ + if (H5Gunlink(grp->hdf_grpid, dim->name) < 0) + return NC_EDIMMETA; + } + + exit: + return retval; +} + /* Normalize a UTF8 name. Put the result in norm_name, which can be * NC_MAX_NAME + 1 in size. This function makes sure the free() gets * called on the return from utf8proc_NFC, and also ensures that the diff --git a/libsrc4/nc4var.c b/libsrc4/nc4var.c index 08a4b3b49..71c5f4db5 100644 --- a/libsrc4/nc4var.c +++ b/libsrc4/nc4var.c @@ -66,9 +66,6 @@ nc4_reopen_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) #ifdef EXTRA_TESTS num_plists--; #endif - - if (var->dimscale) - var->dim[0]->hdf_dimscaleid = var->hdf_datasetid; } return NC_NOERR; @@ -293,8 +290,8 @@ nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) if (suggested_size > var->dim[d]->len) suggested_size = var->dim[d]->len; var->chunksizes[d] = suggested_size ? suggested_size : 1; - LOG((4, "nc_def_var_nc4: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " - "chunksize %ld", var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d])); + LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " + "chunksize %ld", __func__, var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d])); } /* Find total chunk size. */ @@ -348,9 +345,7 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, NC_HDF5_FILE_INFO_T *h5; NC_TYPE_INFO_T *type_info; char norm_name[NC_MAX_NAME + 1]; - int num_unlim = 0; int d; - size_t num_values = 1; int retval; /* Find info for this file and group, and set pointer to each. */ @@ -406,14 +401,10 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, { if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, NULL))) return retval; - if (dim->unlimited) - num_unlim++; - else - num_values *= dim->len; } /* These degrubbing messages sure are handy! */ - LOG((3, "nc_def_var_nc4: name %s type %d ndims %d", norm_name, xtype, ndims)); + LOG((3, "%s: name %s type %d ndims %d", __func__, norm_name, xtype, ndims)); #ifdef LOGGING { int dd; @@ -455,8 +446,6 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, &var->type_info->size))) return retval; } - if (!num_unlim) - var->contiguous = 1; /* Allocate space for dimension information. */ if (ndims) @@ -467,21 +456,49 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, return NC_ENOMEM; } + /* Assign dimensions to the variable */ /* At the same time, check to see if this is a coordinate * variable. If so, it will have the same name as one of its * dimensions. If it is a coordinate var, is it a coordinate var in * the same group as the dim? */ + /* Also, check whether we should use contiguous or chunked storage */ + var->contiguous = 1; for (d = 0; d < ndims; d++) { NC_GRP_INFO_T *dim_grp; + + /* Look up each dimension */ if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, &dim_grp))) return retval; - if (strcmp(dim->name, norm_name) == 0 && dim_grp == grp && d == 0) + + /* Check for dim index 0 having the same name, in the same group */ + if (d == 0 && dim_grp == grp && strcmp(dim->name, norm_name) == 0) { var->dimscale++; dim->coord_var = var; - dim->coord_var_in_grp++; + + /* Use variable's dataset ID for the dimscale ID */ + if (dim->hdf_dimscaleid) + { + /* Detach dimscale from any variables using it */ + if ((retval = rec_detach_scales(grp, dimidsp[d], dim->hdf_dimscaleid)) < 0) + return retval; + + if (H5Dclose(dim->hdf_dimscaleid) < 0) + return NC_EHDFERR; + dim->hdf_dimscaleid = 0; + + /* Now delete the dataset (it will be recreated later, if necessary) */ + if (H5Gunlink(grp->hdf_grpid, dim->name) < 0) + return NC_EDIMMETA; + } } + + /* Check for unlimited dimension and turn off contiguous storage */ + if (dim->unlimited) + var->contiguous = 0; + + /* Track dimensions for variable */ var->dimids[d] = dimidsp[d]; var->dim[d] = dim; } @@ -547,8 +564,8 @@ NC4_def_var(int ncid, const char *name, nc_type xtype, int ndims, NC *nc; NC_HDF5_FILE_INFO_T *h5; - LOG((2, "nc_def_var: ncid 0x%x name %s xtype %d ndims %d", - ncid, name, xtype, ndims)); + LOG((2, "%s: ncid 0x%x name %s xtype %d ndims %d", + __func__, ncid, name, xtype, ndims)); /* If there are dimensions, I need their ids. */ if (ndims && !dimidsp) @@ -596,7 +613,7 @@ NC4_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep, int d; int retval; - LOG((2, "nc_inq_var_all: ncid 0x%x varid %d", ncid, varid)); + LOG((2, "%s: ncid 0x%x varid %d", __func__, ncid, varid)); /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) @@ -726,7 +743,7 @@ nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, int d; int retval; - LOG((2, "nc_def_var_extra: ncid 0x%x varid %d", ncid, varid)); + LOG((2, "%s: ncid 0x%x varid %d", __func__, ncid, varid)); /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) @@ -786,7 +803,7 @@ nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, var->deflate = *deflate; if (*deflate) var->deflate_level = *deflate_level; - LOG((3, "nc_def_var_extra: *deflate_level %d", *deflate_level)); + LOG((3, "%s: *deflate_level %d", __func__, *deflate_level)); } /* Szip in use? */ @@ -1070,7 +1087,7 @@ NC4_inq_varid(int ncid, const char *name, int *varidp) if (!varidp) return NC_NOERR; - LOG((2, "nc_inq_varid: ncid 0x%x name %s", ncid, name)); + LOG((2, "%s: ncid 0x%x name %s", __func__, ncid, name)); /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, NULL))) @@ -1114,8 +1131,8 @@ NC4_rename_var(int ncid, int varid, const char *name) NC_VAR_INFO_T *var; int retval = NC_NOERR; - LOG((2, "nc_rename_var: ncid 0x%x varid %d name %s", - ncid, varid, name)); + LOG((2, "%s: ncid 0x%x varid %d name %s", + __func__, ncid, varid, name)); /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) @@ -1174,6 +1191,38 @@ NC4_rename_var(int ncid, int varid, const char *name) return NC_ENOMEM; strcpy(var->name, name); + /* Check if this was a coordinate variable previously, but names are different now */ + if (var->dimscale && strcmp(var->name, var->dim[0]->name)) + { + /* Break up the coordinate variable */ + if ((retval = nc4_break_coord_var(grp, var, var->dim[0]))) + return retval; + } + + /* Check if this should become a coordinate variable */ + if (!var->dimscale) + { + /* Only variables with >0 dimensions can become coordinate variables */ + if (var->ndims) + { + NC_GRP_INFO_T *dim_grp; + NC_DIM_INFO_T *dim; + + /* Check to see if this is became a coordinate variable. If so, it + * will have the same name as dimension index 0. If it is a + * coordinate var, is it a coordinate var in the same group as the dim? + */ + if ((retval = nc4_find_dim(grp, var->dimids[0], &dim, &dim_grp))) + return retval; + if (strcmp(dim->name, name) == 0 && dim_grp == grp) + { + /* Reform the coordinate variable */ + if ((retval = nc4_reform_coord_var(grp, var, dim))) + return retval; + } + } + } + exit: return retval; } @@ -1191,7 +1240,7 @@ NC4_var_par_access(int ncid, int varid, int par_access) NC_VAR_INFO_T *var; int retval; - LOG((1, "nc_var_par_access: ncid 0x%x varid %d par_access %d", ncid, + LOG((1, "%s: ncid 0x%x varid %d par_access %d", __func__, ncid, varid, par_access)); if (par_access != NC_INDEPENDENT && par_access != NC_COLLECTIVE) @@ -1245,8 +1294,8 @@ nc4_put_vara_tc(int ncid, int varid, nc_type mem_type, int mem_type_is_long, NC_HDF5_FILE_INFO_T *h5; #endif - LOG((2, "nc4_put_vara_tc: ncid 0x%x varid %d mem_type %d mem_type_is_long %d", - ncid, varid, mem_type, mem_type_is_long)); + LOG((2, "%s: ncid 0x%x varid %d mem_type %d mem_type_is_long %d", + __func__, ncid, varid, mem_type, mem_type_is_long)); if (!(nc = nc4_find_nc_file(ncid,NULL))) return NC_EBADID; @@ -1375,8 +1424,8 @@ nc4_get_vara_tc(int ncid, int varid, nc_type mem_type, int mem_type_is_long, NC *nc; NC_HDF5_FILE_INFO_T* h5; - LOG((2, "nc4_get_vara_tc: ncid 0x%x varid %d mem_type %d mem_type_is_long %d", - ncid, varid, mem_type, mem_type_is_long)); + LOG((2, "%s: ncid 0x%x varid %d mem_type %d mem_type_is_long %d", + __func__, ncid, varid, mem_type, mem_type_is_long)); if (!(nc = nc4_find_nc_file(ncid,&h5))) return NC_EBADID; diff --git a/nc_test4/renamegroup.c b/nc_test4/renamegroup.c index c66ea7e7f..3189eecc1 100644 --- a/nc_test4/renamegroup.c +++ b/nc_test4/renamegroup.c @@ -7,6 +7,7 @@ #include #include +#include #define LOGGING #include "netcdf.h" diff --git a/nc_test4/tst_dims.c b/nc_test4/tst_dims.c index dbcfbd1be..03a550b54 100644 --- a/nc_test4/tst_dims.c +++ b/nc_test4/tst_dims.c @@ -15,7 +15,6 @@ #define LEVEL_NAME "level" #define TIME_NAME "time" #define DIM5_NAME "twilight_zone" -#define DIM_NAME "dim" #define LAT_LEN 1 #define LON_LEN 2 #define LEVEL_LEN 3 @@ -171,6 +170,153 @@ main(int argc, char **argv) if (nc_close(ncid)) ERR; } + SUMMARIZE_ERR; + printf("*** Testing renaming dimensions and vars..."); + { +#define FILE_NAME1 "foo1.nc" +#define FILE_NAME2 "foo2.nc" +#define FILE_NAME3 "foo3.nc" +#define FILE_NAME4 "foo4.nc" +#define DIM_NAME "lat_T42" +#define VAR_NAME DIM_NAME +#define DIM_NAME2 "lat" +#define VAR_NAME2 DIM_NAME2 +#define RANK_lat_T42 1 + int ncid, varid, dimid; + int lat_T42_dim; + size_t lat_T42_len = 3; + int lat_T42_id; + int lat_T42_dims[RANK_lat_T42]; + char name[NC_MAX_NAME + 1]; + + /* =========== */ + /* Sub-test #1 */ + /* =========== */ + /* create file with dimension and associated coordinate variable */ + if (nc_create(FILE_NAME1, NC_CLOBBER|NC_NETCDF4|NC_CLASSIC_MODEL, &ncid)) ERR; + if (nc_def_dim(ncid, DIM_NAME, lat_T42_len, &lat_T42_dim)) ERR; + lat_T42_dims[0] = lat_T42_dim; + if (nc_def_var(ncid, VAR_NAME, NC_INT, RANK_lat_T42, lat_T42_dims, &lat_T42_id)) ERR; + if (nc_close(ncid)) ERR; + + + /* reopen file, rename coordinate dimension and then associated variable */ + if (nc_open(FILE_NAME1, NC_WRITE, &ncid)) ERR; + if (nc_inq_dimid(ncid, DIM_NAME, &dimid)) ERR; + if (nc_inq_varid(ncid, VAR_NAME, &varid)) ERR; + if (nc_rename_dim(ncid, dimid, DIM_NAME2)) ERR; + if (nc_rename_var(ncid, varid, VAR_NAME2)) ERR; + if (nc_close(ncid)) ERR; + + + /* reopen file, check coordinate dimension and associated variable names */ + /* Should be just like they created the file with DIM_NAME2 & VAR_NAME2 to + * begin with. + */ + if (nc_open(FILE_NAME1, NC_WRITE, &ncid)) ERR; + if (nc_inq_dimid(ncid, DIM_NAME2, &dimid)) ERR; + if (nc_inq_varid(ncid, VAR_NAME2, &varid)) ERR; + if (nc_inq_dimname(ncid, dimid, name)) ERR; + if (strcmp(name, DIM_NAME2)) ERR; + if (nc_inq_varname(ncid, varid, name)) ERR; + if (strcmp(name, VAR_NAME2)) ERR; + if (nc_close(ncid)) ERR; + + + /* =========== */ + /* Sub-test #2 */ + /* =========== */ + /* create file with dimension and associated coordinate variable */ + if (nc_create(FILE_NAME1, NC_CLOBBER|NC_NETCDF4|NC_CLASSIC_MODEL, &ncid)) ERR; + if (nc_def_dim(ncid, DIM_NAME, lat_T42_len, &lat_T42_dim)) ERR; + lat_T42_dims[0] = lat_T42_dim; + if (nc_def_var(ncid, VAR_NAME, NC_INT, RANK_lat_T42, lat_T42_dims, &lat_T42_id)) ERR; + if (nc_close(ncid)) ERR; + + + /* reopen file, just rename coordinate dimension */ + if (nc_open(FILE_NAME1, NC_WRITE, &ncid)) ERR; + if (nc_inq_dimid(ncid, DIM_NAME, &dimid)) ERR; + if (nc_rename_dim(ncid, dimid, DIM_NAME2)) ERR; + if (nc_close(ncid)) ERR; + + + /* reopen file, check coordinate dimension and associated variable names */ + /* Should be just like the file was created with DIM_NAME2 to begin with */ + if (nc_open(FILE_NAME1, NC_WRITE, &ncid)) ERR; + if (nc_inq_dimid(ncid, DIM_NAME2, &dimid)) ERR; + if (nc_inq_varid(ncid, VAR_NAME, &varid)) ERR; + if (nc_inq_dimname(ncid, dimid, name)) ERR; + if (strcmp(name, DIM_NAME2)) ERR; + if (nc_inq_varname(ncid, varid, name)) ERR; + if (strcmp(name, VAR_NAME)) ERR; + if (nc_close(ncid)) ERR; + + + /* =========== */ + /* Sub-test #3 */ + /* =========== */ + /* create file with dimension and associated coordinate variable */ + if (nc_create(FILE_NAME1, NC_CLOBBER|NC_NETCDF4|NC_CLASSIC_MODEL, &ncid)) ERR; + if (nc_def_dim(ncid, DIM_NAME, lat_T42_len, &lat_T42_dim)) ERR; + lat_T42_dims[0] = lat_T42_dim; + if (nc_def_var(ncid, VAR_NAME, NC_INT, RANK_lat_T42, lat_T42_dims, &lat_T42_id)) ERR; + if (nc_close(ncid)) ERR; + + + /* reopen file, just rename variable */ + if (nc_open(FILE_NAME1, NC_WRITE, &ncid)) ERR; + if (nc_inq_varid(ncid, VAR_NAME, &varid)) ERR; + if (nc_rename_var(ncid, varid, VAR_NAME2)) ERR; + if (nc_close(ncid)) ERR; + + + /* reopen file, check coordinate dimension and associated variable names */ + /* Should be just like the file was created with VAR_NAME2 to begin with */ + if (nc_open(FILE_NAME1, NC_WRITE, &ncid)) ERR; + if (nc_inq_dimid(ncid, DIM_NAME, &dimid)) ERR; + if (nc_inq_varid(ncid, VAR_NAME2, &varid)) ERR; + if (nc_inq_dimname(ncid, dimid, name)) ERR; + if (strcmp(name, DIM_NAME)) ERR; + if (nc_inq_varname(ncid, varid, name)) ERR; + if (strcmp(name, VAR_NAME2)) ERR; + if (nc_close(ncid)) ERR; + + + /* =========== */ + /* Sub-test #4 */ + /* =========== */ + /* create file with dimension and associated coordinate variable */ + if (nc_create(FILE_NAME1, NC_CLOBBER|NC_NETCDF4|NC_CLASSIC_MODEL, &ncid)) ERR; + if (nc_def_dim(ncid, DIM_NAME, lat_T42_len, &lat_T42_dim)) ERR; + lat_T42_dims[0] = lat_T42_dim; + if (nc_def_var(ncid, VAR_NAME, NC_INT, RANK_lat_T42, lat_T42_dims, &lat_T42_id)) ERR; + if (nc_close(ncid)) ERR; + + + /* reopen file, rename associated variable and then coordinate dimension */ + if (nc_open(FILE_NAME1, NC_WRITE, &ncid)) ERR; + if (nc_inq_dimid(ncid, DIM_NAME, &dimid)) ERR; + if (nc_inq_varid(ncid, VAR_NAME, &varid)) ERR; + if (nc_rename_var(ncid, varid, VAR_NAME2)) ERR; + if (nc_rename_dim(ncid, dimid, DIM_NAME2)) ERR; + if (nc_close(ncid)) ERR; + + + /* reopen file, check coordinate dimension and associated variable names */ + /* Should be just like they created the file with DIM_NAME2 & VAR_NAME2 to + * begin with. + */ + if (nc_open(FILE_NAME1, NC_WRITE, &ncid)) ERR; + if (nc_inq_dimid(ncid, DIM_NAME2, &dimid)) ERR; + if (nc_inq_varid(ncid, VAR_NAME2, &varid)) ERR; + if (nc_inq_dimname(ncid, dimid, name)) ERR; + if (strcmp(name, DIM_NAME2)) ERR; + if (nc_inq_varname(ncid, varid, name)) ERR; + if (strcmp(name, VAR_NAME2)) ERR; + if (nc_close(ncid)) ERR; + } + SUMMARIZE_ERR; printf("*** Testing file with just one unlimited dimension..."); { diff --git a/nc_test4/tst_dims2.c b/nc_test4/tst_dims2.c index 77aee5fa6..d7ead94f1 100644 --- a/nc_test4/tst_dims2.c +++ b/nc_test4/tst_dims2.c @@ -68,9 +68,6 @@ main(int argc, char **argv) * Christian! Next time I'm in Rostock I'll come by and buy you * a beer. ;-) */ #define TL 15 -#define SHUFFLE 0 -#define DEFLATE 1 -#define DEFLATE_LEVEL 5 int ncid; int time_dim; int tl_dim; @@ -137,9 +134,6 @@ main(int argc, char **argv) * Christian! Next time I'm in Rostock I'll come by and buy you * a beer. ;-) */ #define TL 15 -#define SHUFFLE 0 -#define DEFLATE 1 -#define DEFLATE_LEVEL 5 #define NDIMS2 2 #define NUM_TIMES 16 int ncid; @@ -247,7 +241,6 @@ main(int argc, char **argv) SUMMARIZE_ERR; printf("*** Checking multiple unlimited dimensions..."); { -#define MAX(x,y) ((x)>(y)?(x):(y)) #define NDIMS 2 #define MAX_VALUES 3 diff --git a/nc_test4/tst_parallel3.c b/nc_test4/tst_parallel3.c index 2adc3d1ab..27f9c98f0 100644 --- a/nc_test4/tst_parallel3.c +++ b/nc_test4/tst_parallel3.c @@ -53,6 +53,7 @@ int test_pio(int); int test_pio_attr(int); int test_pio_big(int); int test_pio_hyper(int); +int test_pio_extend(int); char* getenv_all(MPI_Comm comm, int root, const char* name); int facc_type; diff --git a/ncgen/genlib.c b/ncgen/genlib.c index 9243aefbd..9b6ae60f7 100644 --- a/ncgen/genlib.c +++ b/ncgen/genlib.c @@ -17,6 +17,7 @@ void define_netcdf(void) { char filename[2048+1]; + const char *fname; /* Rule for specifying the dataset name: 1. use -o name @@ -28,37 +29,43 @@ define_netcdf(void) */ if(netcdf_name) { /* -o flag name */ strcpy(filename,netcdf_name); + fname = filename; } else { /* construct a usable output file name */ if (cdlname != NULL && strcmp(cdlname,"-") != 0) {/* cmd line name */ char* p; + strncpy(filename,cdlname,2048); /* remove any suffix and prefix*/ p = strrchr(filename,'.'); if(p != NULL) {*p= '\0';} p = strrchr(filename,'/'); - if(p != NULL) {strncpy(filename,p+1,2048);} + if(p != NULL) + fname = p + 1; + else + fname = filename; } else {/* construct name from dataset name */ strncpy(filename,datasetname,2048); /* Reserve space for extension, terminating '\0' */ + fname = filename; } /* Append the proper extension */ - strcat(filename,binary_ext); + strcat(fname,binary_ext); } /* Execute exactly one of these */ #ifdef ENABLE_C - if (l_flag == L_C) gen_ncc(filename); else /* create C code to create netcdf */ + if (l_flag == L_C) gen_ncc(fname); else /* create C code to create netcdf */ #endif #ifdef ENABLE_F77 - if (l_flag == L_F77) gen_ncf77(filename); else /* create Fortran code */ + if (l_flag == L_F77) gen_ncf77(fname); else /* create Fortran code */ #endif #ifdef ENABLE_JAVA if(l_flag == L_JAVA) { - gen_ncjava(filename); + gen_ncjava(fname); } else #endif /* Binary is the default */ #ifdef ENABLE_BINARY - gen_netcdf(filename); /* create netcdf */ + gen_netcdf(fname); /* create netcdf */ #else derror("No language specified"); #endif diff --git a/ncgen3/ncgen.h b/ncgen3/ncgen.h index 92cb4732e..5d5a5c895 100644 --- a/ncgen3/ncgen.h +++ b/ncgen3/ncgen.h @@ -9,6 +9,7 @@ #define MAX_NC_ATTSIZE 20000 /* max size of attribute (for ncgen) */ #define MAXTRST 5000 /* max size of string value (for ncgen) */ +#include "config.h" #include "generic.h" extern int ncid; /* handle for netCDF */