mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-11-21 03:13:42 +08:00
Merge pull request #1521 from ckhroulev/netcdf4-repeated-attribute-modification
Improve the fix for #350 included in #1119
This commit is contained in:
commit
1a6351dab2
@ -512,7 +512,6 @@ put_att_grpa(NC_GRP_INFO_T *grp, int varid, NC_ATT_INFO_T *att)
|
||||
hid_t existing_att_typeid = 0, existing_attid = 0, existing_spaceid = 0;
|
||||
hsize_t dims[1]; /* netcdf attributes always 1-D. */
|
||||
htri_t attr_exists;
|
||||
int reuse_att = 0; /* Will be true if we can re-use an existing att. */
|
||||
void *data;
|
||||
int phoney_data = 99;
|
||||
int retval = NC_NOERR;
|
||||
@ -617,26 +616,49 @@ put_att_grpa(NC_GRP_INFO_T *grp, int varid, NC_ATT_INFO_T *att)
|
||||
if ((npoints = H5Sget_simple_extent_npoints(existing_spaceid)) < 0)
|
||||
BAIL(NC_EATTMETA);
|
||||
|
||||
/* Delete the attribute. */
|
||||
if (file_typeid != existing_att_typeid || npoints != att->len)
|
||||
/* For text attributes the size is specified in the datatype
|
||||
and it is enough to compare types using H5Tequal(). */
|
||||
if (!H5Tequal(file_typeid, existing_att_typeid) ||
|
||||
(att->nc_typeid != NC_CHAR && npoints != att->len))
|
||||
{
|
||||
/* The attribute exists but we cannot re-use it. */
|
||||
|
||||
/* Delete the attribute. */
|
||||
if (H5Adelete(locid, att->hdr.name) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Re-create the attribute with the type and length
|
||||
reflecting the new value (or values). */
|
||||
if ((attid = H5Acreate(locid, att->hdr.name, file_typeid, spaceid,
|
||||
H5P_DEFAULT)) < 0)
|
||||
BAIL(NC_EATTMETA);
|
||||
|
||||
/* Write the values, (even if length is zero). */
|
||||
if (H5Awrite(attid, file_typeid, data) < 0)
|
||||
BAIL(NC_EATTMETA);
|
||||
}
|
||||
else
|
||||
{
|
||||
reuse_att++;
|
||||
/* The attribute exists and we can re-use it. */
|
||||
|
||||
/* Write the values, re-using the existing attribute. */
|
||||
if (H5Awrite(existing_attid, file_typeid, data) < 0)
|
||||
BAIL(NC_EATTMETA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The attribute does not exist yet. */
|
||||
|
||||
/* Create the attribute. */
|
||||
if ((attid = H5Acreate(locid, att->hdr.name, file_typeid, spaceid,
|
||||
H5P_DEFAULT)) < 0)
|
||||
BAIL(NC_EATTMETA);
|
||||
/* Create the attribute. */
|
||||
if ((attid = H5Acreate(locid, att->hdr.name, file_typeid, spaceid,
|
||||
H5P_DEFAULT)) < 0)
|
||||
BAIL(NC_EATTMETA);
|
||||
|
||||
/* Write the values, (even if length is zero). */
|
||||
if (H5Awrite(attid, file_typeid, data) < 0)
|
||||
BAIL(NC_EATTMETA);
|
||||
/* Write the values, (even if length is zero). */
|
||||
if (H5Awrite(attid, file_typeid, data) < 0)
|
||||
BAIL(NC_EATTMETA);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (file_typeid && H5Tclose(file_typeid))
|
||||
|
@ -424,5 +424,99 @@ main(int argc, char **argv)
|
||||
free(data_in);
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
printf("*** testing modification of an attribute 2^16 times (changing size)...");
|
||||
{
|
||||
/* This test documents that if the size of an attribute changes
|
||||
* from one modification to the next we have to delete and
|
||||
* re-create it, incrementing HDF5's attribute creation order
|
||||
* index. In this case after about 2^16 modifications this
|
||||
* index reaches its maximum, making it impossible to modify
|
||||
* this file's metadata because nc_enddef() will fail. */
|
||||
int ncid = -1, i = -1, error_code = NC_NOERR;
|
||||
int data[2] = {1, 2};
|
||||
|
||||
/* Create a file. Note that we use a different file name here
|
||||
* because we will not be able to close this file. */
|
||||
if (nc_create("tst_att_modification.nc", NC_NETCDF4|NC_CLOBBER, &ncid)) ERR;
|
||||
if (nc_enddef(ncid)) ERR;
|
||||
|
||||
/* Modify an attribute 2^16 times. */
|
||||
for (i = 0; i < 65536; ++i)
|
||||
{
|
||||
if (nc_redef(ncid)) ERR;
|
||||
|
||||
/* Note that the attribute size changes every time. */
|
||||
if (nc_put_att_int(ncid, NC_GLOBAL, "attribute", NC_INT,
|
||||
1 + i % 2, data)) ERR;
|
||||
|
||||
/* nc_enddef() synchronizes attributes. */
|
||||
error_code = nc_enddef(ncid);
|
||||
|
||||
/* After a number of iterations nc_enddef() will fail with
|
||||
* NC_EATTMETA. */
|
||||
if (error_code == NC_EATTMETA)
|
||||
break;
|
||||
|
||||
/* Catch other errors. */
|
||||
if (error_code != NC_NOERR) ERR;
|
||||
}
|
||||
|
||||
/* nc_close() will fail too: just like nc_enddef() it tries to
|
||||
* write dirty attributes to disc. */
|
||||
if (nc_close(ncid) != NC_EATTMETA) ERR;
|
||||
|
||||
/* In this test reaching the end of the loop without encountering
|
||||
* NC_EATTMETA is a failure. */
|
||||
if (error_code != NC_EATTMETA) ERR;
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
printf("*** testing modification of a scalar attribute 2^16 times (same type and size)...");
|
||||
{
|
||||
/* This test ensures that a scalar attribute can be modified
|
||||
* 2^16 times as long as its type and size remain the same. */
|
||||
int ncid = -1, i = -1;
|
||||
|
||||
/* Create a file. */
|
||||
if (nc_create(FILE_NAME, NC_NETCDF4|NC_CLOBBER, &ncid)) ERR;
|
||||
if (nc_enddef(ncid)) ERR;
|
||||
|
||||
/* Modify an attribute 2^16 times. */
|
||||
for (i = 0; i < 65536; ++i)
|
||||
{
|
||||
if (nc_redef(ncid)) ERR;
|
||||
/* All built-in attribute types except for NC_CHAR (but
|
||||
* including NC_STRING) use the same logic so it is enough
|
||||
* to test nc_put_att_int(). */
|
||||
if (nc_put_att_int(ncid, NC_GLOBAL, "attribute", NC_INT, 1, &i)) ERR;
|
||||
/* nc_enddef() synchronizes attributes. */
|
||||
if (nc_enddef(ncid)) ERR;
|
||||
}
|
||||
|
||||
if (nc_close(ncid)) ERR;
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
printf("*** testing modification of a text attribute 2^16 times (same size)...");
|
||||
{
|
||||
/* This test ensures that a text attribute can be modified
|
||||
* 2^16 times as long as its size remains the same. */
|
||||
int ncid = -1, i = -1;
|
||||
const char *string = "test string"; /* 11 characters */
|
||||
|
||||
/* Create a file. */
|
||||
if (nc_create(FILE_NAME, NC_NETCDF4|NC_CLOBBER, &ncid)) ERR;
|
||||
if (nc_enddef(ncid)) ERR;
|
||||
|
||||
/* Modify an attribute 2^16 times. */
|
||||
for (i = 0; i < 65536; ++i)
|
||||
{
|
||||
if (nc_redef(ncid)) ERR;
|
||||
if (nc_put_att_text(ncid, NC_GLOBAL, "attribute", 11, string)) ERR;
|
||||
/* nc_enddef() synchronizes attributes */
|
||||
if (nc_enddef(ncid)) ERR;
|
||||
}
|
||||
|
||||
if (nc_close(ncid)) ERR;
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
FINAL_RESULTS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user