diff options
Diffstat (limited to 'src/H5D.c')
-rw-r--r-- | src/H5D.c | 414 |
1 files changed, 403 insertions, 11 deletions
@@ -1,14 +1,16 @@ -/**************************************************************************** -* NCSA HDF * -* Software Development Group * -* National Center for Supercomputing Applications * -* University of Illinois at Urbana-Champaign * -* 605 E. Springfield, Champaign IL 61820 * -* * -* For conditions of distribution and use, see the accompanying * -* hdf/COPYING file. * -* * -****************************************************************************/ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* $Id$ */ @@ -1459,6 +1461,396 @@ done: FUNC_LEAVE(ret_value); } +H5D_t * +H5D_create_cache_update(H5G_entry_t *loc, const char *name, const H5T_t *type, + const H5S_t *space, const H5P_genplist_t *plist) +{ + H5D_t *new_dset = NULL; + H5D_t *ret_value = NULL; + int i, ndims; + hsize_t comp_data_size; + unsigned u; + hsize_t max_dim[H5O_LAYOUT_NDIMS] = { 0 }; + H5O_efl_t efl; + H5F_t *f = NULL; + H5O_pline_t dcpl_pline; + H5D_layout_t dcpl_layout; + int chunk_ndims = 0; + hsize_t chunk_size[32] = { 0 }; + H5D_alloc_time_t alloc_time; + H5D_fill_time_t fill_time; + H5O_fill_t fill_prop = { NULL, 0, NULL }; + H5O_fill_new_t fill = { NULL, 0, NULL, H5D_ALLOC_TIME_LATE, H5D_FILL_TIME_ALLOC, TRUE }; + H5D_fill_value_t fill_status; + H5P_genplist_t *new_plist; /* New Property list */ + size_t ohdr_size = H5D_MINHDR_SIZE; /* Size of dataset's object header */ + + FUNC_ENTER_NOAPI(H5D_create_cache_update, NULL); + + /* check args */ + assert (loc); + assert (name && *name); + assert (type); + assert (space); + + if (H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &dcpl_pline) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve pipeline filter"); + + if (H5P_get(plist, H5D_CRT_LAYOUT_NAME, &dcpl_layout) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve layout"); + + if (dcpl_pline.nfilters > 0 && H5D_CHUNKED != dcpl_layout) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, NULL, + "filters can only be used with chunked layout"); + + if (H5P_get(plist, H5D_CRT_ALLOC_TIME_NAME, &alloc_time) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve space allocation time"); + + /* Check if the alloc_time is the default and set it accordingly */ + if (alloc_time == H5D_ALLOC_TIME_DEFAULT) + switch (dcpl_layout) { + case H5D_COMPACT: + alloc_time = H5D_ALLOC_TIME_EARLY; + break; + case H5D_CONTIGUOUS: + alloc_time = H5D_ALLOC_TIME_LATE; + break; + case H5D_CHUNKED: + alloc_time = H5D_ALLOC_TIME_INCR; + break; + default: + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, NULL, "not implemented yet"); + } + + /* Don't allow compact datasets to allocate space later */ + if (dcpl_layout == H5D_COMPACT && alloc_time != H5D_ALLOC_TIME_EARLY) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, NULL, + "compact dataset doesn't support late space allocation"); + + /* What file is the dataset being added to? */ + if ((f = H5G_insertion_file(loc, name)) == NULL) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to locate insertion point"); + + /* If MPIO or MPIPOSIX is used, no filter support yet. */ + if ((IS_H5FD_MPIO(f) || IS_H5FD_MPIPOSIX(f)) && dcpl_pline.nfilters > 0) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, NULL, + "Parallel I/O does not support filters yet"); + + /* Check if this dataset is going into a parallel file and set space allocation time */ + if (IS_H5FD_MPIO(f) || IS_H5FD_MPIPOSIX(f)) + alloc_time = H5D_ALLOC_TIME_EARLY; + + if (H5P_get(plist, H5D_CRT_FILL_TIME_NAME, &fill_time) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve fill time"); + + if (fill_time == H5D_FILL_TIME_NEVER && H5T_detect_class(type, H5T_VLEN)) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, NULL, + "Dataset doesn't support VL datatype when fill value is not defined"); + + /* Initialize the dataset object */ + if (NULL == (new_dset = H5D_new(dcpl_id))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); + + /* Check if the datatype is "sensible" for use in a dataset */ + if (H5T_is_sensible(type) != TRUE) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "datatype is not sensible"); + + /* Copy datatype for dataset */ + if ((new_dset->type = H5T_copy(type, H5T_COPY_ALL)) == NULL) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy datatype"); + + /* Mark any VL datatypes as being on disk now */ + if (H5T_vlen_mark(new_dset->type, f, H5T_VLEN_DISK) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid VL location"); + + /* Get new dataset's property list object */ + if ((new_plist = H5I_object(new_dset->dcpl_id)) == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, + "can't get dataset creation property list"); + + /* Set the alloc_time for the dataset, in case the default was used */ + if (H5P_set(new_plist, H5D_CRT_ALLOC_TIME_NAME, &alloc_time) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "can't set allocation time"); + + if (H5P_get(new_plist, H5D_CRT_CHUNK_DIM_NAME, &chunk_ndims) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve layout"); + + if (H5P_get(new_plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve external file list"); + + /* Total raw data size */ + if (H5P_get(new_plist, H5D_CRT_LAYOUT_NAME, &new_dset->layout.type) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve layout"); + + new_dset->layout.ndims = H5S_get_simple_extent_ndims(space) + 1; + assert((unsigned)(new_dset->layout.ndims) <= NELMTS(new_dset->layout.dim)); + new_dset->layout.dim[new_dset->layout.ndims - 1] = H5T_get_size(new_dset->type); + new_dset->layout.addr = HADDR_UNDEF; /* Initialize to no address */ + +/************************************************************* + * Begin Cache Update + *************************************************************/ + + switch (new_dset->layout.type) { + case H5D_CONTIGUOUS: + /* + * The maximum size of the dataset cannot exceed the storage size. + * Also, only the slowest varying dimension of a simple data space + * can be extendible. + */ + if ((ndims = H5S_get_simple_extent_dims(space, new_dset->layout.dim, max_dim)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to initialize contiguous storage"); + + for (i = 1; i < ndims; i++) + if (max_dim[i] > new_dset->layout.dim[i]) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "only the first dimension can be extendible"); + + if (efl.nused > 0) { + hsize_t max_points = H5S_get_npoints_max (space); + hsize_t max_storage = H5O_efl_total_size (&efl); + + if (H5S_UNLIMITED == max_points) { + if (H5O_EFL_UNLIMITED!=max_storage) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unlimited data space but finite storage"); + } else if (max_points * H5T_get_size (type) < max_points) { + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "data space * type size overflowed"); + } else if (max_points * H5T_get_size (type) > max_storage) { + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "data space size exceeds external storage size"); + } + } else if (ndims > 0 && max_dim[0] > new_dset->layout.dim[0]) { + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, NULL, + "extendible contiguous non-external dataset"); + } + + break; + + case H5D_CHUNKED: + /* + * Chunked storage allows any type of data space extension, so we + * don't even bother checking. + */ + if (chunk_ndims != H5S_get_simple_extent_ndims(space)) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, NULL, + "dimensionality of chunks doesn't match the data space"); + + if (efl.nused > 0) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, NULL, + "external storage not supported with chunked layout"); + + /* + * The chunk size of a dimension with a fixed size cannot exceed + * the maximum dimension size + */ + if (H5P_get(new_plist, H5D_CRT_CHUNK_SIZE_NAME, chunk_size) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve chunk size"); + + if (H5S_get_simple_extent_dims(space, NULL, max_dim)<0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to query maximum dimensions"); + + for (u = 0; u < new_dset->layout.ndims - 1; u++) + if (max_dim[u] != H5S_UNLIMITED && max_dim[u] < chunk_size[u]) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "chunk size must be <= maximum dimension size for fixed-sized dimensions"); + + /* Set the dataset's chunk sizes from the property list's chunk sizes */ + for (u = 0; u < new_dset->layout.ndims - 1; u++) + new_dset->layout.dim[u] = chunk_size[u]; + + break; + + case H5D_COMPACT: + /* + * Compact dataset is stored in dataset object header message of + * layout. + */ + new_dset->layout.size = H5S_get_simple_extent_npoints(space) * + H5T_get_size(type); + + /* + * Verify data size is smaller than maximum header message size + * (64KB) minus other layout message fields. + */ + comp_data_size = H5O_MAX_SIZE-H5O_layout_meta_size(f, &new_dset->layout); + + if (new_dset->layout.size > comp_data_size) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "compact dataset size is bigger than header message maximum size"); + + if ((ndims = H5S_get_simple_extent_dims(space, new_dset->layout.dim, max_dim)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to initialize dimension size of compact dataset storage"); + + /* remember to check if size is small enough to fit header message */ + ohdr_size += new_dset->layout.size; + break; + + default: + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, NULL, "not implemented yet"); + } /* end switch */ + + /* Create (open for write access) an object header */ + if (H5O_create(f, ohdr_size, &new_dset->ent) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to create dataset object header"); + + /* + * Retrieve properties of fill value and others. Copy them into new + * fill value struct. Convert the fill value to the dataset type and + * write the message + */ + if (H5P_get(new_plist, H5D_CRT_ALLOC_TIME_NAME, &alloc_time) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve space allocation time"); + + if (H5P_get(new_plist, H5D_CRT_FILL_TIME_NAME, &fill_time) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve fill time"); + + if (H5P_fill_value_defined(new_plist, &fill_status)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't tell if fill value defined"); + + if (fill_status== H5D_FILL_VALUE_DEFAULT || fill_status==H5D_FILL_VALUE_USER_DEFINED) { + if (H5P_get(new_plist, H5D_CRT_FILL_VALUE_NAME, &fill_prop) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't retrieve fill value"); + + if (H5O_copy(H5O_FILL, &fill_prop, &fill) == NULL) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT,NULL, "unable to copy fill value"); + + if (fill_prop.buf && fill_prop.size > 0 && + H5O_fill_convert(&fill, new_dset->type) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to convert fill value to dataset type"); + + fill.fill_defined = TRUE; + } else if (fill_status == H5D_FILL_VALUE_UNDEFINED) { + fill.size = -1; + fill.type = fill.buf = NULL; + fill.fill_defined = FALSE; + } else { + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, NULL, + "unable to determine if fill value is defined"); + } /* end else */ + + fill.alloc_time = alloc_time; + fill.fill_time = fill_time; + + if (fill.fill_defined == FALSE && fill_time != H5D_FILL_TIME_NEVER) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT,NULL, "unable to create dataset"); + + /* Write new fill value message */ + if (H5O_modify(&new_dset->ent, H5O_FILL_NEW, 0, H5O_FLAG_CONSTANT, &fill) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to update fill value header message"); + + H5O_reset(H5O_FILL, &fill_prop); + + if (fill.buf && (NULL==H5O_copy(H5O_FILL, &fill, &fill_prop))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to copy fill value"); + + H5O_reset(H5O_FILL_NEW, &fill); + + /* Write old fill value */ + if (fill_prop.buf && + H5O_modify(&new_dset->ent, H5O_FILL, 0, H5O_FLAG_CONSTANT, &fill_prop) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to update fill value header message"); + + if (H5P_set(new_plist, H5D_CRT_FILL_VALUE_NAME, &fill_prop) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, NULL, "can't set fill value"); + + /* Update the type and space header messages */ + if (H5O_modify(&new_dset->ent, H5O_DTYPE, 0, + H5O_FLAG_CONSTANT | H5O_FLAG_SHARED, new_dset->type) < 0 || + H5S_modify(&new_dset->ent, space) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to update type or space header messages"); + + /* Update the filters message */ + if (H5P_get(new_plist, H5D_CRT_DATA_PIPELINE_NAME, &dcpl_pline) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "Can't retrieve pipeline filter"); + + if (dcpl_pline.nfilters>0 && + H5O_modify (&new_dset->ent, H5O_PLINE, 0, H5O_FLAG_CONSTANT, &dcpl_pline) < 0) + HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, NULL, "unable to update filter header message"); + + /* Add a modification time message. */ + if (H5O_touch(&new_dset->ent, TRUE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to update modification time message"); + + /* Give the dataset a name */ + if (H5G_insert(loc, name, &new_dset->ent) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to name dataset"); + + /* + * Allocate storage if space allocate time is early; otherwise delay + * allocation until later. + */ + if (alloc_time == H5D_ALLOC_TIME_EARLY) + if (H5D_alloc_storage(f, new_dset, H5D_ALLOC_CREATE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to initialize storage"); + + /* Update external storage message */ + if (efl.nused > 0) { + size_t heap_size = H5HL_ALIGN(1); + + for (i = 0; i < efl.nused; ++i) + heap_size += H5HL_ALIGN(HDstrlen(efl.slot[i].name) + 1); + + if (H5HL_create(f, heap_size, &efl.heap_addr /*out*/) < 0 || + (size_t)(-1) == H5HL_insert(f, efl.heap_addr, 1, "")) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to create external file list name heap"); + + for (i = 0; i < efl.nused; ++i) { + size_t offset = H5HL_insert(f, efl.heap_addr, + HDstrlen(efl.slot[i].name) + 1, + efl.slot[i].name); + + assert(0 == efl.slot[i].name_offset); + + if ((size_t)(-1) == offset) + HGOTO_ERROR(H5E_EFL, H5E_CANTINIT, NULL, "unable to insert URL into name heap"); + + efl.slot[i].name_offset = offset; + } /* end for */ + + if (H5O_modify(&new_dset->ent, H5O_EFL, 0, H5O_FLAG_CONSTANT, &efl) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, + "unable to update external file list message"); + } /* end if */ + + /* Update layout message */ + if (H5D_COMPACT != new_dset->layout.type && + H5O_modify(&new_dset->ent, H5O_LAYOUT, 0, 0, &new_dset->layout) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, NULL, "unable to update layout"); + +/************************************************************* + * Cache Updated + *************************************************************/ + + /* Success */ + ret_value = new_dset; + +done: + if (!ret_value && new_dset) { + if (new_dset->type) + H5T_close(new_dset->type); + + if (H5F_addr_defined(new_dset->ent.header)) + H5O_close(&(new_dset->ent)); + + new_dset->ent.file = NULL; + H5FL_FREE(H5D_t,new_dset); + } + + FUNC_LEAVE(ret_value); +} + /*------------------------------------------------------------------------- * Function: H5D_create |